diff --git a/AUTHORS b/AUTHORS
index 347737b..3c47ef5 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -623,6 +623,7 @@
 Loo Rong Jie <loorongjie@gmail.com>
 Lorenzo Stoakes <lstoakes@gmail.com>
 Lu Guanqun <guanqun.lu@gmail.com>
+Luc Shi <lei.a.shi@intel.com>
 Luca Di Domenico <luca94dd@gmail.com>
 Lucie Brozkova <lucinka.brozkova@gmail.com>
 Luiz Von Dentz <luiz.von.dentz@intel.com>
@@ -1108,6 +1109,7 @@
 Yi Sun <ratsunny@gmail.com>
 Yichen Jiang <jiangyichen123@gmail.com>
 Yifei Yu <yuyifei@xiaomi.com>
+Yi Zhang <yi.y.zhang@intel.com>
 Yizhou Jiang <yizhou.jiang@intel.com>
 Yoav Weiss <yoav@yoav.ws>
 Yoav Zilberberg <yoav.zilberberg@gmail.com>
diff --git a/DEPS b/DEPS
index a166802..1f406f2 100644
--- a/DEPS
+++ b/DEPS
@@ -206,11 +206,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': '82f373c0d7135b213f2d5b10a0b7bf7eade8ad97',
+  'skia_revision': '2d2f82c00aeb8d82f37911621a287fe7cee00dbc',
   # 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': '5c5a797885ab5f35d91688d8c001976d2322b798',
+  'v8_revision': 'd20e0a345b623a1373a8833f30c5f7f153b902d7',
   # 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.
@@ -218,22 +218,22 @@
   # 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': 'c55cd6b43d55fb0ed6e59a8a5c92be82258f5587',
+  'angle_revision': '9d160b0bba68f5cebb8f66c894c84f95b608eb72',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'df17a76102dfabb3f1bd6e51449cece9f77b45e3',
+  'swiftshader_revision': '85d9d5d4bbc6ef1a8382df21d92bc6dc0bed4057',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '299fe92af960a7fd785db410a263a022edc648bd',
+  'pdfium_revision': 'e03bf7b4af92edce27642b529982cd27b680a789',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
   #
   # Note this revision should be updated with
   # third_party/boringssl/roll_boringssl.py, not roll-dep.
-  'boringssl_revision': '3743aafdacff2f7b083615a043a37101f740fa53',
+  'boringssl_revision': 'a673d02458b1b7d897084266b93d5c610e36bd17',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -269,7 +269,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': '3fc3588cdf370107ad68e67c5e497eeb4faf658c',
+  'catapult_revision': '2fb0633adec8dcad80fad839ccf265f4b3c8c787',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -277,7 +277,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': '1227ffd7958584eb486cb065a50630ae7a06eb27',
+  'devtools_frontend_revision': 'bd66f2d951865e98f1924808f3f14c5c179b8cd7',
   # 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.
@@ -329,7 +329,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': 'e557087870b0db11f232ce5825f88d8037e10e7c',
+  'dawn_revision': 'e9c99e93e75ec13ecf143478b9defe92230fc83e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -368,7 +368,7 @@
   'ukey2_revision': '0275885d8e6038c39b8a8ca55e75d1d4d1727f47',
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'tint_revision': '7156d3e3140b361c34503e518fa078bd0189981f',
+  'tint_revision': '4f79c84050287dab127ba5410e770889ed11cb05',
 
   # TODO(crbug.com/941824): The values below need to be kept in sync
   # between //DEPS and //buildtools/DEPS, so if you're updating one,
@@ -1343,7 +1343,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': 'kSNKixLzCdPhPfzn5a8Sdbbj9YRIyrm_8oIZKZlBjzAC'
+              'version': 'exAX_yeKLNYEK0NGmhD6PCExVZm6XY2aCPioGGLAHlYC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1569,7 +1569,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@4deb1ed9573dc77388ef895e2d1f4ee6f976e895',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@a87909398b713aea9b1aee41fe7cebbedc627e58',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index e43d47e..4588b25 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -363,7 +363,6 @@
   '^chrome/browser/signin/',
   '^chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc',
   '^chrome/browser/ssl/',
-  '^chrome/browser/subresource_filter/',
   '^chrome/browser/supervised_user/',
   '^chrome/browser/sync_file_system/',
   '^chrome/browser/sync/',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 67a12412..a82cc758 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -2165,6 +2165,7 @@
     "system/phonehub/phone_hub_ui_controller_unittest.cc",
     "system/phonehub/phone_status_view_unittest.cc",
     "system/phonehub/quick_actions_view_unittest.cc",
+    "system/phonehub/silence_phone_quick_action_controller_unittest.cc",
     "system/phonehub/task_continuation_view_unittest.cc",
     "system/power/backlights_forced_off_setter_unittest.cc",
     "system/power/peripheral_battery_notifier_unittest.cc",
diff --git a/ash/shelf/login_shelf_view.cc b/ash/shelf/login_shelf_view.cc
index 949058a..ca52383 100644
--- a/ash/shelf/login_shelf_view.cc
+++ b/ash/shelf/login_shelf_view.cc
@@ -93,7 +93,7 @@
       session_manager::SessionState::OOBE) {
     return SkColorSetA(SK_ColorBLACK, 16);  // 6% opacity
   }
-  return DeprecatedGetLoginBackgroundBaseColor(kLoginBackgroundBaseColor);
+  return DeprecatedGetLoginBackgroundBaseColor(kLoginButtonBackgroundBaseColor);
 }
 
 LoginMetricsRecorder::ShelfButtonClickTarget GetUserClickTarget(int button_id) {
diff --git a/ash/style/default_color_constants.h b/ash/style/default_color_constants.h
index 1a13e10..0d0e242a 100644
--- a/ash/style/default_color_constants.h
+++ b/ash/style/default_color_constants.h
@@ -19,6 +19,8 @@
 constexpr SkColor kLoginShelfButtonLabelColor = gfx::kGoogleGrey100;
 constexpr SkColor kLoginShelfButtonIconColor = SkColorSetRGB(0xEB, 0xEA, 0xED);
 constexpr SkColor kLoginBackgroundBaseColor = SK_ColorBLACK;
+constexpr SkColor kLoginButtonBackgroundBaseColor =
+    SkColorSetA(SK_ColorWHITE, 26);
 
 // Colors for shelf.
 constexpr SkColor kDefaultShelfInkDropColor = SK_ColorBLACK;
diff --git a/ash/system/phonehub/locate_phone_quick_action_controller.cc b/ash/system/phonehub/locate_phone_quick_action_controller.cc
index b4c1509..fc57ba0 100644
--- a/ash/system/phonehub/locate_phone_quick_action_controller.cc
+++ b/ash/system/phonehub/locate_phone_quick_action_controller.cc
@@ -7,6 +7,7 @@
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/phonehub/quick_action_item.h"
+#include "ash/system/phonehub/silence_phone_quick_action_controller.h"
 #include "base/timer/timer.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -24,14 +25,19 @@
 using Status = chromeos::phonehub::FindMyDeviceController::Status;
 
 LocatePhoneQuickActionController::LocatePhoneQuickActionController(
-    chromeos::phonehub::FindMyDeviceController* find_my_device_controller)
-    : find_my_device_controller_(find_my_device_controller) {
+    chromeos::phonehub::FindMyDeviceController* find_my_device_controller,
+    SilencePhoneQuickActionController* silence_phone_controller)
+    : find_my_device_controller_(find_my_device_controller),
+      silence_phone_controller_(silence_phone_controller) {
   DCHECK(find_my_device_controller_);
+  DCHECK(silence_phone_controller_);
   find_my_device_controller_->AddObserver(this);
+  silence_phone_controller_->AddObserver(this);
 }
 
 LocatePhoneQuickActionController::~LocatePhoneQuickActionController() {
   find_my_device_controller_->RemoveObserver(this);
+  silence_phone_controller_->RemoveObserver(this);
 }
 
 QuickActionItem* LocatePhoneQuickActionController::CreateItem() {
@@ -55,20 +61,35 @@
   find_my_device_controller_->RequestNewPhoneRingingState(!is_now_enabled);
 }
 
+void LocatePhoneQuickActionController::OnSilencePhoneItemStateChanged() {
+  is_silence_enabled_ = silence_phone_controller_->IsItemEnabled();
+  UpdateState();
+}
+
 void LocatePhoneQuickActionController::OnPhoneRingingStateChanged() {
-  switch (find_my_device_controller_->GetPhoneRingingStatus()) {
-    case Status::kRingingOff:
-      state_ = ActionState::kOff;
-      break;
-    case Status::kRingingOn:
-      state_ = ActionState::kOn;
-      break;
-    case Status::kRingingNotAvailable:
-      item_->SetEnabled(false);
-      return;
+  UpdateState();
+}
+
+void LocatePhoneQuickActionController::UpdateState() {
+  // Disable Locate Phone if Silence Phone is on, otherwise change accordingly
+  // based on status from FindMyDeviceController.
+  if (is_silence_enabled_) {
+    state_ = ActionState::kNotAvailable;
+  } else {
+    switch (find_my_device_controller_->GetPhoneRingingStatus()) {
+      case Status::kRingingOff:
+        state_ = ActionState::kOff;
+        break;
+      case Status::kRingingOn:
+        state_ = ActionState::kOn;
+        break;
+      case Status::kRingingNotAvailable:
+        state_ = ActionState::kNotAvailable;
+        break;
+    }
   }
+
   SetItemState(state_);
-  item_->SetEnabled(true);
 
   // If |requested_state_| correctly resembles the current state, reset it and
   // the timer.
@@ -83,6 +104,9 @@
   int state_text_id;
   int sub_label_text;
   switch (state) {
+    case ActionState::kNotAvailable:
+      item_->SetEnabled(false);
+      return;
     case ActionState::kOff:
       icon_enabled = false;
       state_text_id = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_DISABLED_STATE_TOOLTIP;
@@ -95,6 +119,7 @@
       break;
   }
 
+  item_->SetEnabled(true);
   item_->SetToggled(icon_enabled);
   item_->SetSubLabel(l10n_util::GetStringUTF16(sub_label_text));
   base::string16 tooltip_state =
diff --git a/ash/system/phonehub/locate_phone_quick_action_controller.h b/ash/system/phonehub/locate_phone_quick_action_controller.h
index 52b72b6..955c338 100644
--- a/ash/system/phonehub/locate_phone_quick_action_controller.h
+++ b/ash/system/phonehub/locate_phone_quick_action_controller.h
@@ -5,7 +5,7 @@
 #ifndef ASH_SYSTEM_PHONEHUB_LOCATE_PHONE_QUICK_ACTION_CONTROLLER_H_
 #define ASH_SYSTEM_PHONEHUB_LOCATE_PHONE_QUICK_ACTION_CONTROLLER_H_
 
-#include "ash/system/phonehub/quick_action_controller_base.h"
+#include "ash/system/phonehub/silence_phone_quick_action_controller.h"
 #include "chromeos/components/phonehub/find_my_device_controller.h"
 
 namespace base {
@@ -17,10 +17,12 @@
 // Controller of a quick action item that toggles Locate phone mode.
 class LocatePhoneQuickActionController
     : public QuickActionControllerBase,
+      public SilencePhoneQuickActionController::Observer,
       public chromeos::phonehub::FindMyDeviceController::Observer {
  public:
-  explicit LocatePhoneQuickActionController(
-      chromeos::phonehub::FindMyDeviceController* find_my_device_controller);
+  LocatePhoneQuickActionController(
+      chromeos::phonehub::FindMyDeviceController* find_my_device_controller,
+      SilencePhoneQuickActionController* silence_phone_controller);
   ~LocatePhoneQuickActionController() override;
   LocatePhoneQuickActionController(LocatePhoneQuickActionController&) = delete;
   LocatePhoneQuickActionController operator=(
@@ -30,13 +32,20 @@
   QuickActionItem* CreateItem() override;
   void OnButtonPressed(bool is_now_enabled) override;
 
+  // SilencePhoneQuickActionController::Observer:
+  void OnSilencePhoneItemStateChanged() override;
+
   // chromeos::phonehub::FindMyDeviceController::Observer:
   void OnPhoneRingingStateChanged() override;
 
  private:
   // All the possible states that the locate phone button can be viewed. Each
   // state has a corresponding icon, labels and tooltip view.
-  enum class ActionState { kOff, kOn };
+  enum class ActionState { kNotAvailable, kOff, kOn };
+
+  // Compute and update the state of the item according to Silence Phone item
+  // and FindMyDeviceController.
+  void UpdateState();
 
   // Set the item (including icon, label and tooltips) to a certain state.
   void SetItemState(ActionState state);
@@ -47,11 +56,15 @@
 
   chromeos::phonehub::FindMyDeviceController* find_my_device_controller_ =
       nullptr;
+  SilencePhoneQuickActionController* silence_phone_controller_ = nullptr;
   QuickActionItem* item_ = nullptr;
 
   // Keep track the current state of the item.
   ActionState state_;
 
+  // Keep track the state of Silence Phone item.
+  bool is_silence_enabled_;
+
   // State that user requests when clicking the button.
   base::Optional<ActionState> requested_state_;
 
diff --git a/ash/system/phonehub/quick_actions_view.cc b/ash/system/phonehub/quick_actions_view.cc
index df68b14..e3e66a80 100644
--- a/ash/system/phonehub/quick_actions_view.cc
+++ b/ash/system/phonehub/quick_actions_view.cc
@@ -38,20 +38,25 @@
 QuickActionsView::~QuickActionsView() = default;
 
 void QuickActionsView::InitQuickActionItems() {
-  enable_hotspot_ =
-      AddItem(std::make_unique<EnableHotspotQuickActionController>(
-          phone_hub_manager_->GetTetherController()));
-  silence_phone_ = AddItem(std::make_unique<SilencePhoneQuickActionController>(
-      phone_hub_manager_->GetDoNotDisturbController()));
-  locate_phone_ = AddItem(std::make_unique<LocatePhoneQuickActionController>(
-      phone_hub_manager_->GetFindMyDeviceController()));
-}
+  auto enable_hotspot_controller =
+      std::make_unique<EnableHotspotQuickActionController>(
+          phone_hub_manager_->GetTetherController());
+  enable_hotspot_ = AddChildView(enable_hotspot_controller->CreateItem());
+  quick_action_controllers_.push_back(std::move(enable_hotspot_controller));
 
-QuickActionItem* QuickActionsView::AddItem(
-    std::unique_ptr<QuickActionControllerBase> controller) {
-  auto* item = AddChildView(controller->CreateItem());
-  quick_action_controllers_.push_back(std::move(controller));
-  return item;
+  auto silence_phone_controller =
+      std::make_unique<SilencePhoneQuickActionController>(
+          phone_hub_manager_->GetDoNotDisturbController());
+  silence_phone_ = AddChildView(silence_phone_controller->CreateItem());
+
+  auto locate_phone_controller =
+      std::make_unique<LocatePhoneQuickActionController>(
+          phone_hub_manager_->GetFindMyDeviceController(),
+          silence_phone_controller.get());
+  locate_phone_ = AddChildView(locate_phone_controller->CreateItem());
+
+  quick_action_controllers_.push_back(std::move(silence_phone_controller));
+  quick_action_controllers_.push_back(std::move(locate_phone_controller));
 }
 
 }  // namespace ash
diff --git a/ash/system/phonehub/quick_actions_view.h b/ash/system/phonehub/quick_actions_view.h
index 1aa3ccc0..7fda6b6 100644
--- a/ash/system/phonehub/quick_actions_view.h
+++ b/ash/system/phonehub/quick_actions_view.h
@@ -32,10 +32,6 @@
   // Add all the quick actions items to the view.
   void InitQuickActionItems();
 
-  // Helper function to add an item to the view given its controller.
-  QuickActionItem* AddItem(
-      std::unique_ptr<QuickActionControllerBase> controller);
-
   // Controllers of quick actions items. Owned by this.
   std::vector<std::unique_ptr<QuickActionControllerBase>>
       quick_action_controllers_;
diff --git a/ash/system/phonehub/quick_actions_view_unittest.cc b/ash/system/phonehub/quick_actions_view_unittest.cc
index 7baf51515..3d06312 100644
--- a/ash/system/phonehub/quick_actions_view_unittest.cc
+++ b/ash/system/phonehub/quick_actions_view_unittest.cc
@@ -105,10 +105,14 @@
                                                              DummyEvent());
   EXPECT_TRUE(dnd_controller()->IsDndEnabled());
 
+  // Locate phone should be disabled when do not disturb is enabled.
+  EXPECT_FALSE(actions_view()->locate_phone_for_testing()->GetEnabled());
+
   // Togge again to disable.
   actions_view()->silence_phone_for_testing()->ButtonPressed(nullptr,
                                                              DummyEvent());
   EXPECT_FALSE(dnd_controller()->IsDndEnabled());
+  EXPECT_TRUE(actions_view()->locate_phone_for_testing()->GetEnabled());
 
   // Test the error state.
   dnd_controller()->SetShouldRequestFail(true);
diff --git a/ash/system/phonehub/silence_phone_quick_action_controller.cc b/ash/system/phonehub/silence_phone_quick_action_controller.cc
index 6b7701f..678da30 100644
--- a/ash/system/phonehub/silence_phone_quick_action_controller.cc
+++ b/ash/system/phonehub/silence_phone_quick_action_controller.cc
@@ -32,6 +32,18 @@
   dnd_controller_->RemoveObserver(this);
 }
 
+void SilencePhoneQuickActionController::AddObserver(Observer* observer) {
+  observer_list_.AddObserver(observer);
+}
+
+void SilencePhoneQuickActionController::RemoveObserver(Observer* observer) {
+  observer_list_.RemoveObserver(observer);
+}
+
+bool SilencePhoneQuickActionController::IsItemEnabled() {
+  return item_->IsToggled();
+}
+
 QuickActionItem* SilencePhoneQuickActionController::CreateItem() {
   DCHECK(!item_);
   item_ = new QuickActionItem(this, IDS_ASH_PHONE_HUB_SILENCE_PHONE_TITLE,
@@ -90,6 +102,9 @@
   item_->SetIconTooltip(
       l10n_util::GetStringFUTF16(IDS_ASH_PHONE_HUB_QUICK_ACTIONS_TOGGLE_TOOLTIP,
                                  item_->GetItemLabel(), tooltip_state));
+
+  for (auto& observer : observer_list_)
+    observer.OnSilencePhoneItemStateChanged();
 }
 
 void SilencePhoneQuickActionController::CheckRequestedState() {
diff --git a/ash/system/phonehub/silence_phone_quick_action_controller.h b/ash/system/phonehub/silence_phone_quick_action_controller.h
index 38c2b8c..c44cd2fd 100644
--- a/ash/system/phonehub/silence_phone_quick_action_controller.h
+++ b/ash/system/phonehub/silence_phone_quick_action_controller.h
@@ -6,6 +6,8 @@
 #define ASH_SYSTEM_PHONEHUB_SILENCE_PHONE_QUICK_ACTION_CONTROLLER_H_
 
 #include "ash/system/phonehub/quick_action_controller_base.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "chromeos/components/phonehub/do_not_disturb_controller.h"
 
 namespace base {
@@ -15,10 +17,18 @@
 namespace ash {
 
 // Controller of a quick action item that toggles silence phone mode.
-class SilencePhoneQuickActionController
+class ASH_EXPORT SilencePhoneQuickActionController
     : public QuickActionControllerBase,
       public chromeos::phonehub::DoNotDisturbController::Observer {
  public:
+  class Observer : public base::CheckedObserver {
+   public:
+    ~Observer() override = default;
+
+    // Called when the state of the item has changed.
+    virtual void OnSilencePhoneItemStateChanged() = 0;
+  };
+
   explicit SilencePhoneQuickActionController(
       chromeos::phonehub::DoNotDisturbController* dnd_controller);
   ~SilencePhoneQuickActionController() override;
@@ -27,6 +37,12 @@
   SilencePhoneQuickActionController operator=(
       SilencePhoneQuickActionController&) = delete;
 
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
+  // Return true if the item is enabled/toggled.
+  bool IsItemEnabled();
+
   // QuickActionControllerBase:
   QuickActionItem* CreateItem() override;
   void OnButtonPressed(bool is_now_enabled) override;
@@ -59,6 +75,9 @@
   // if the requested state is similar to the current state after the button is
   // pressed for a certain time.
   std::unique_ptr<base::OneShotTimer> check_requested_state_timer_;
+
+  // Registered observers.
+  base::ObserverList<Observer> observer_list_;
 };
 
 }  // namespace ash
diff --git a/ash/system/phonehub/silence_phone_quick_action_controller_unittest.cc b/ash/system/phonehub/silence_phone_quick_action_controller_unittest.cc
new file mode 100644
index 0000000..0dae8d45
--- /dev/null
+++ b/ash/system/phonehub/silence_phone_quick_action_controller_unittest.cc
@@ -0,0 +1,83 @@
+// 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 "ash/system/phonehub/silence_phone_quick_action_controller.h"
+
+#include "ash/test/ash_test_base.h"
+#include "chromeos/components/phonehub/fake_do_not_disturb_controller.h"
+
+namespace ash {
+
+class SilencePhoneQuickActionControllerTest
+    : public AshTestBase,
+      public SilencePhoneQuickActionController::Observer {
+ public:
+  SilencePhoneQuickActionControllerTest() = default;
+
+  ~SilencePhoneQuickActionControllerTest() override = default;
+
+  // AshTestBase:
+  void SetUp() override {
+    AshTestBase::SetUp();
+
+    dnd_controller_ =
+        std::make_unique<chromeos::phonehub::FakeDoNotDisturbController>();
+    controller_ = std::make_unique<SilencePhoneQuickActionController>(
+        dnd_controller_.get());
+
+    controller_->AddObserver(this);
+    controller_->CreateItem();
+  }
+
+  void TearDown() override {
+    controller_->RemoveObserver(this);
+    controller_.reset();
+    dnd_controller_.reset();
+    AshTestBase::TearDown();
+  }
+
+ protected:
+  // SilencePhoneQuickActionController::Observer:
+  void OnSilencePhoneItemStateChanged() override { ++num_calls_; }
+
+  SilencePhoneQuickActionController* controller() { return controller_.get(); }
+
+  chromeos::phonehub::FakeDoNotDisturbController* dnd_controller() {
+    return dnd_controller_.get();
+  }
+
+  size_t GetNumObserverCalls() { return num_calls_; }
+
+ private:
+  std::unique_ptr<SilencePhoneQuickActionController> controller_;
+  std::unique_ptr<chromeos::phonehub::FakeDoNotDisturbController>
+      dnd_controller_;
+  size_t num_calls_ = 0;
+};
+
+TEST_F(SilencePhoneQuickActionControllerTest, ItemStateChanged) {
+  // Set request to fail to avoid triggering state's changes by the model.
+  dnd_controller()->SetShouldRequestFail(true);
+
+  // Initially, there's one observer call during initiation.
+  EXPECT_EQ(1u, GetNumObserverCalls());
+
+  // Press the button to enabled state will trigger observer.
+  controller()->OnButtonPressed(false /* is_now_enabled */);
+  EXPECT_EQ(2u, GetNumObserverCalls());
+
+  // Item state changed to enabled.
+  EXPECT_TRUE(controller()->IsItemEnabled());
+
+  // Press the button to disabled state will trigger observer.
+  controller()->OnButtonPressed(true /* is_now_enabled */);
+  EXPECT_EQ(3u, GetNumObserverCalls());
+
+  // Item state changed to disabled.
+  EXPECT_FALSE(controller()->IsItemEnabled());
+
+  dnd_controller()->SetShouldRequestFail(false);
+}
+
+}  // namespace ash
diff --git a/base/BUILD.gn b/base/BUILD.gn
index d08fb6e..e7262be 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -3072,6 +3072,10 @@
       "win/wmi_unittest.cc",
       "win/wrapped_window_proc_unittest.cc",
     ]
+
+    if (enable_cet_shadow_stack) {
+      sources += [ "win/cet_shadow_stack_unittest.cc" ]
+    }
   }
 
   if (is_linux || is_chromeos) {
diff --git a/base/android/java/src/org/chromium/base/BundleUtils.java b/base/android/java/src/org/chromium/base/BundleUtils.java
index 5496e02..613f0ce 100644
--- a/base/android/java/src/org/chromium/base/BundleUtils.java
+++ b/base/android/java/src/org/chromium/base/BundleUtils.java
@@ -98,10 +98,24 @@
 
     /* Returns absolute path to a native library in a feature module. */
     @CalledByNative
-    private static String getNativeLibraryPath(String libraryName) {
+    public static String getNativeLibraryPath(String libraryName) {
         try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
-            return ((BaseDexClassLoader) ContextUtils.getApplicationContext().getClassLoader())
-                    .findLibrary(libraryName);
+            ClassLoader classLoader = ContextUtils.getApplicationContext().getClassLoader();
+            String path = getNativeLibraryPathFromClassLoader(classLoader, libraryName);
+            // TODO(b/171269960): Isolated split class loaders have an empty library path, so check
+            // the parent class loader as well.
+            if (path == null) {
+                path = getNativeLibraryPathFromClassLoader(classLoader.getParent(), libraryName);
+            }
+            return path;
         }
     }
+
+    private static String getNativeLibraryPathFromClassLoader(
+            ClassLoader classLoader, String libraryName) {
+        if (classLoader == null) {
+            return null;
+        }
+        return ((BaseDexClassLoader) classLoader).findLibrary(libraryName);
+    }
 }
diff --git a/base/metrics/ukm_source_id.h b/base/metrics/ukm_source_id.h
index 7cf9725..7f29a31 100644
--- a/base/metrics/ukm_source_id.h
+++ b/base/metrics/ukm_source_id.h
@@ -76,11 +76,6 @@
     return value_ != other.value_;
   }
 
-  // Allow coercive comparisons to simplify test migration.
-  // TODO(crbug/873866): Remove these once callers are migrated.
-  constexpr bool operator==(int64_t other) const { return value_ == other; }
-  constexpr bool operator!=(int64_t other) const { return value_ == other; }
-
   // Extract the Type of the SourceId.
   Type GetType() const;
 
diff --git a/base/win/async_operation.h b/base/win/async_operation.h
index 3dc2801..b2ad6f0 100644
--- a/base/win/async_operation.h
+++ b/base/win/async_operation.h
@@ -110,7 +110,7 @@
         base::BindOnce(&AsyncOperation::OnResult, weak_factory_.GetWeakPtr());
   }
 
-  ~AsyncOperation() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); }
+  ~AsyncOperation() override { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); }
 
   // ABI::Windows::Foundation::IAsyncOperation:
   IFACEMETHODIMP put_Completed(Handler* handler) override {
diff --git a/base/win/cet_shadow_stack_unittest.cc b/base/win/cet_shadow_stack_unittest.cc
new file mode 100644
index 0000000..b21a3a7
--- /dev/null
+++ b/base/win/cet_shadow_stack_unittest.cc
@@ -0,0 +1,39 @@
+// 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 <Windows.h>
+#include <intrin.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+void* return_address;
+
+__attribute__((noinline)) void Bug() {
+  void* pvAddressOfReturnAddress = _AddressOfReturnAddress();
+  if (!return_address)
+    return_address = *(void**)pvAddressOfReturnAddress;
+  else
+    *(void**)pvAddressOfReturnAddress = return_address;
+}
+
+__attribute__((noinline)) void A() {
+  Bug();
+}
+
+__attribute__((noinline)) void B() {
+  Bug();
+}
+
+TEST(CET, ShadowStack) {
+  // TODO(ajgo): Check that it's enabled by OS.
+  A();
+  EXPECT_DEATH(B(), "");
+}
+}  // namespace
+}  // namespace win
+}  // namespace base
diff --git a/base/win/pe_image_reader.cc b/base/win/pe_image_reader.cc
index 4fd841c..97fdd6b 100644
--- a/base/win/pe_image_reader.cc
+++ b/base/win/pe_image_reader.cc
@@ -35,7 +35,7 @@
 template <class OPTIONAL_HEADER_TYPE>
 class PeImageReader::OptionalHeaderImpl : public PeImageReader::OptionalHeader {
  public:
-  typedef OptionalHeaderTraits<OPTIONAL_HEADER_TYPE> TraitsType;
+  using TraitsType = OptionalHeaderTraits<OPTIONAL_HEADER_TYPE>;
 
   explicit OptionalHeaderImpl(const uint8_t* optional_header_start)
       : optional_header_(reinterpret_cast<const OPTIONAL_HEADER_TYPE*>(
@@ -62,8 +62,7 @@
   DISALLOW_COPY_AND_ASSIGN(OptionalHeaderImpl);
 };
 
-PeImageReader::PeImageReader()
-    : image_data_(), image_size_(), validation_state_() {}
+PeImageReader::PeImageReader() {}
 
 PeImageReader::~PeImageReader() {
   Clear();
@@ -249,11 +248,13 @@
 
   std::unique_ptr<OptionalHeader> optional_header;
   if (*optional_header_magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
-    optional_header.reset(new OptionalHeaderImpl<IMAGE_OPTIONAL_HEADER32>(
-        image_data_ + optional_header_offset));
+    optional_header =
+        std::make_unique<OptionalHeaderImpl<IMAGE_OPTIONAL_HEADER32>>(
+            image_data_ + optional_header_offset);
   } else if (*optional_header_magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
-    optional_header.reset(new OptionalHeaderImpl<IMAGE_OPTIONAL_HEADER64>(
-        image_data_ + optional_header_offset));
+    optional_header =
+        std::make_unique<OptionalHeaderImpl<IMAGE_OPTIONAL_HEADER64>>(
+            image_data_ + optional_header_offset);
   } else {
     return false;
   }
diff --git a/base/win/pe_image_reader.h b/base/win/pe_image_reader.h
index d6acb8d7..72f8739 100644
--- a/base/win/pe_image_reader.h
+++ b/base/win/pe_image_reader.h
@@ -36,11 +36,11 @@
   // |certificate_data_size| bytes). |context| is the value provided by the
   // caller to EnumCertificates(). Implementations must return true to continue
   // the enumeration, or false to abort.
-  typedef bool (*EnumCertificatesCallback)(uint16_t revision,
-                                           uint16_t certificate_type,
-                                           const uint8_t* certificate_data,
-                                           size_t certificate_data_size,
-                                           void* context);
+  using EnumCertificatesCallback = bool (*)(uint16_t revision,
+                                            uint16_t certificate_type,
+                                            const uint8_t* certificate_data,
+                                            size_t certificate_data_size,
+                                            void* context);
 
   PeImageReader();
   ~PeImageReader();
@@ -91,7 +91,7 @@
   // An interface to an image's optional header.
   class OptionalHeader {
    public:
-    virtual ~OptionalHeader() {}
+    virtual ~OptionalHeader() = default;
 
     virtual WordSize GetWordSize() = 0;
 
@@ -161,9 +161,9 @@
     return true;
   }
 
-  const uint8_t* image_data_;
-  size_t image_size_;
-  uint32_t validation_state_;
+  const uint8_t* image_data_ = nullptr;
+  size_t image_size_ = 0;
+  uint32_t validation_state_ = 0;
   std::unique_ptr<OptionalHeader> optional_header_;
   DISALLOW_COPY_AND_ASSIGN(PeImageReader);
 };
diff --git a/base/win/pe_image_reader_unittest.cc b/base/win/pe_image_reader_unittest.cc
index d9fe0e11..292ad950 100644
--- a/base/win/pe_image_reader_unittest.cc
+++ b/base/win/pe_image_reader_unittest.cc
@@ -186,8 +186,8 @@
   }
 
  protected:
-  CertificateReceiver() {}
-  virtual ~CertificateReceiver() {}
+  CertificateReceiver() = default;
+  virtual ~CertificateReceiver() = default;
   virtual bool OnCertificate(uint16_t revision,
                              uint16_t certificate_type,
                              const uint8_t* certificate_data,
@@ -196,7 +196,7 @@
 
 class MockCertificateReceiver : public CertificateReceiver {
  public:
-  MockCertificateReceiver() {}
+  MockCertificateReceiver() = default;
   MOCK_METHOD4(OnCertificate, bool(uint16_t, uint16_t, const uint8_t*, size_t));
 
  private:
diff --git a/base/win/scoped_safearray.h b/base/win/scoped_safearray.h
index 1233753a..b0335e4 100644
--- a/base/win/scoped_safearray.h
+++ b/base/win/scoped_safearray.h
@@ -40,11 +40,7 @@
     using pointer = value_type*;
     using const_pointer = const value_type*;
 
-    LockScope()
-        : safearray_(nullptr),
-          vartype_(VT_EMPTY),
-          array_(nullptr),
-          array_size_(0U) {}
+    LockScope() = default;
 
     LockScope(LockScope<ElementVartype>&& other)
         : safearray_(std::exchange(other.safearray_, nullptr)),
@@ -107,10 +103,10 @@
       array_size_ = 0U;
     }
 
-    SAFEARRAY* safearray_;
-    VARTYPE vartype_;
-    pointer array_;
-    size_t array_size_;
+    SAFEARRAY* safearray_ = nullptr;
+    VARTYPE vartype_ = VT_EMPTY;
+    pointer array_ = nullptr;
+    size_t array_size_ = 0U;
 
     friend class ScopedSafearray;
     DISALLOW_COPY_AND_ASSIGN(LockScope);
diff --git a/base/win/win_util.h b/base/win/win_util.h
index a727af78..08095c3 100644
--- a/base/win/win_util.h
+++ b/base/win/win_util.h
@@ -230,7 +230,7 @@
 // The original state is restored upon destruction.
 class BASE_EXPORT ScopedDomainStateForTesting {
  public:
-  ScopedDomainStateForTesting(bool state);
+  explicit ScopedDomainStateForTesting(bool state);
   ~ScopedDomainStateForTesting();
 
  private:
@@ -242,7 +242,7 @@
 // object.  The original state is restored upon destruction.
 class BASE_EXPORT ScopedDeviceRegisteredWithManagementForTesting {
  public:
-  ScopedDeviceRegisteredWithManagementForTesting(bool state);
+  explicit ScopedDeviceRegisteredWithManagementForTesting(bool state);
   ~ScopedDeviceRegisteredWithManagementForTesting();
 
  private:
diff --git a/build/android/pylib/local/emulator/avd.py b/build/android/pylib/local/emulator/avd.py
index 881bff3a..452887c 100644
--- a/build/android/pylib/local/emulator/avd.py
+++ b/build/android/pylib/local/emulator/avd.py
@@ -258,6 +258,7 @@
 
         config_ini_contents.update({
             'disk.dataPartition.size': '4G',
+            'hw.keyboard': 'yes',
             'hw.lcd.density': density,
             'hw.lcd.height': height,
             'hw.lcd.width': width,
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 212c949..e0984fa 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -315,6 +315,7 @@
   "//build/config:feature_flags",
   "//build/config/compiler:afdo",
   "//build/config/compiler:afdo_optimize_size",
+  "//build/config/compiler:cet_shadow_stack",
   "//build/config/compiler:compiler",
   "//build/config/compiler:compiler_arm_fpu",
   "//build/config/compiler:compiler_arm_thumb",
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index bc176d5..4c363465c 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -255,7 +255,7 @@
 
     # Enables Java library desugaring.
     # This will cause an extra classes.dex file to appear in every apk.
-    enable_jdk_library_desugaring = true
+    enable_jdk_library_desugaring = false
   }
 
   # Host stuff -----------------------------------------------------------------
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index b23c95d..82474ee 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -2280,6 +2280,13 @@
   # build reproducibility. Debuggers look for pdb files next to executables,
   # so there's no downside to always using this.
   ldflags = [ "/pdbaltpath:%_PDB%" ]
+
+  if (enable_cet_shadow_stack && use_lld) {
+    # TODO(crbug.com/1136664): Investigate why Windows does not recognize
+    # CET in some binaries linked by LLD with /DEBUG.
+    # This is the best place for work around as it follows all /DEBUG uses.
+    ldflags += [ "/DEBUG:NONE" ]
+  }
 }
 
 # Full symbols.
@@ -2544,3 +2551,10 @@
 
   flags = [ "CLANG_PGO=$chrome_pgo_phase" ]
 }
+
+config("cet_shadow_stack") {
+  if (enable_cet_shadow_stack && is_win) {
+    assert(target_cpu == "x64")
+    ldflags = [ "/CETCOMPAT" ]
+  }
+}
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 9b019c1e..d6a3a9a 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -97,6 +97,14 @@
   # Where to redirect clang crash diagnoses
   clang_diagnostic_dir =
       rebase_path("//tools/clang/crashreports", root_build_dir)
+
+  # Experimental option to mark binaries as compatible with Shadow
+  # Stack of Control-flow Enforcement Technology (CET). If Windows version
+  # and hardware supports the feature and it's enabled by OS then additional
+  # additional validation of return address will be performed as mitigation
+  # against Return-oriented programming (ROP).
+  # https://chromium.googlesource.com/chromium/src/+/master/docs/design/sandbox.md#cet-shadow-stack
+  enable_cet_shadow_stack = false
 }
 
 assert(!is_cfi || use_thin_lto, "CFI requires ThinLTO")
diff --git a/build/fuchsia/device_target.py b/build/fuchsia/device_target.py
index 17310d5..da7ed16 100644
--- a/build/fuchsia/device_target.py
+++ b/build/fuchsia/device_target.py
@@ -28,8 +28,8 @@
 # Number of failed connection attempts before redirecting system logs to stdout.
 CONNECT_RETRY_COUNT_BEFORE_LOGGING = 10
 
-# Number of seconds to wait when querying a list of all devices over mDNS.
-_LIST_DEVICES_TIMEOUT_SECS = 3
+# Number of seconds to wait for device discovery.
+BOOT_DISCOVERY_TIMEOUT_SECS = 2 * 60
 
 # Time between a reboot command is issued and when connection attempts from the
 # host begin.
@@ -166,13 +166,19 @@
     dev_finder_path = GetHostToolPathFromPlatform('device-finder')
 
     if self._node_name:
-      command = [dev_finder_path, 'resolve',
-                 '-device-limit', '1',  # Exit early as soon as a host is found.
-                 self._node_name]
+      command = [
+          dev_finder_path,
+          'resolve',
+          '-timeout',
+          "%ds" % BOOT_DISCOVERY_TIMEOUT_SECS / BOOT_DISCOVERY_ATTEMPTS,
+          '-device-limit',
+          '1',  # Exit early as soon as a host is found.
+          self._node_name
+      ]
     else:
       command = [
           dev_finder_path, 'list', '-full', '-timeout',
-          "%ds" % _LIST_DEVICES_TIMEOUT_SECS
+          "%ds" % BOOT_DISCOVERY_TIMEOUT_SECS / BOOT_DISCOVERY_ATTEMPTS
       ]
 
     proc = subprocess.Popen(command,
@@ -180,7 +186,6 @@
                             stderr=open(os.devnull, 'w'))
 
     output = set(proc.communicate()[0].strip().split('\n'))
-
     if proc.returncode != 0:
       return False
 
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 54c3bda..90fb5ca 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20201020.2.1
+0.20201020.3.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 54c3bda..90fb5ca 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20201020.2.1
+0.20201020.3.1
diff --git a/build/lacros/mojo_connection_lacros_launcher.py b/build/lacros/mojo_connection_lacros_launcher.py
index ca10a28..5e2b74c 100755
--- a/build/lacros/mojo_connection_lacros_launcher.py
+++ b/build/lacros/mojo_connection_lacros_launcher.py
@@ -3,7 +3,8 @@
 # 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.
-"""Helps launch lacros-chrome with mojo connection established on Linux.
+"""Helps launch lacros-chrome with mojo connection established on Linux
+  or Chrome OS. Use on Chrome OS is for dev purposes.
 
   The main use case is to be able to launch lacros-chrome in a debugger.
 
@@ -47,12 +48,15 @@
   # This function is borrowed from with modifications:
   # https://docs.python.org/3/library/socket.html#socket.socket.recvmsg
   fds = array.array("i")  # Array of ints
-  _, ancdata, _, _ = sock.recvmsg(0, socket.CMSG_LEN(fds.itemsize))
+  # Along with the file descriptor, ash-chrome also sends the version in the
+  # regular data.
+  version, ancdata, _, _ = sock.recvmsg(1, socket.CMSG_LEN(fds.itemsize))
   for cmsg_level, cmsg_type, cmsg_data in ancdata:
     if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS:
       assert len(cmsg_data) == fds.itemsize, 'Expecting exactly 1 FD'
       fds.frombytes(cmsg_data[:fds.itemsize])
 
+  assert version == b'\x00', 'Expecting version code to be 0'
   assert len(list(fds)) == 1, 'Expecting exactly 1 FD'
   return os.fdopen(list(fds)[0])
 
diff --git a/chrome/VERSION b/chrome/VERSION
index dc02332..cba10da 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=88
 MINOR=0
-BUILD=4298
+BUILD=4299
 PATCH=0
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 3d6d1de..e3b9dc7 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1552,6 +1552,7 @@
   "java/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandler.java",
   "java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java",
   "java/src/org/chromium/chrome/browser/toolbar/NewTabButton.java",
+  "java/src/org/chromium/chrome/browser/toolbar/NewTabPageDelegate.java",
   "java/src/org/chromium/chrome/browser/toolbar/ProgressAnimationSmooth.java",
   "java/src/org/chromium/chrome/browser/toolbar/SettableThemeColorProvider.java",
   "java/src/org/chromium/chrome/browser/toolbar/TabCountProvider.java",
diff --git a/chrome/android/expectations/monochrome_public_bundle.arm64.libs_and_assets.expected b/chrome/android/expectations/monochrome_public_bundle.arm64.libs_and_assets.expected
index 28ace4dc..771e205 100644
--- a/chrome/android/expectations/monochrome_public_bundle.arm64.libs_and_assets.expected
+++ b/chrome/android/expectations/monochrome_public_bundle.arm64.libs_and_assets.expected
@@ -3,8 +3,13 @@
 apk_path=lib/armeabi-v7a/libarcore_sdk_c.so, compress=False, alignment=4096
 apk_path=lib/armeabi-v7a/libcrashpad_handler_trampoline.so, compress=False, alignment=4096
 apk_path=lib/armeabi-v7a/libmonochrome.so, compress=False, alignment=4096
+apk_path=lib/armeabi-v7a/libmonochrome_cablev2_authenticator_partition.so, compress=False, alignment=4096
+apk_path=lib/armeabi-v7a/libmonochrome_stack_unwinder_partition.so, compress=False, alignment=4096
+apk_path=lib/armeabi-v7a/libmonochrome_test_dummy_partition.so, compress=False, alignment=4096
+apk_path=lib/armeabi-v7a/libmonochrome_vr_partition.so, compress=False, alignment=4096
 apk_path=assets/chrome_100_percent.pak, compress=False, alignment=4
 apk_path=assets/icudtl.dat, compress=False, alignment=4
+apk_path=assets/icudtl_extra.dat, compress=False, alignment=4
 apk_path=assets/locales/af.pak, compress=False, alignment=4
 apk_path=assets/locales/am.pak, compress=False, alignment=4
 apk_path=assets/locales/ar.pak, compress=False, alignment=4
diff --git a/chrome/android/expectations/trichrome_chrome_bundle.arm64.libs_and_assets.expected b/chrome/android/expectations/trichrome_chrome_bundle.arm64.libs_and_assets.expected
index e9c8441..1f7aec2b 100644
--- a/chrome/android/expectations/trichrome_chrome_bundle.arm64.libs_and_assets.expected
+++ b/chrome/android/expectations/trichrome_chrome_bundle.arm64.libs_and_assets.expected
@@ -1,6 +1,11 @@
 apk_path=lib/armeabi-v7a/libarcore_sdk_c.so, compress=False, alignment=4096
 apk_path=lib/armeabi-v7a/libchromium_android_linker.so, compress=False, alignment=4096
+apk_path=lib/armeabi-v7a/libmonochrome_cablev2_authenticator_partition.so, compress=False, alignment=4096
+apk_path=lib/armeabi-v7a/libmonochrome_stack_unwinder_partition.so, compress=False, alignment=4096
+apk_path=lib/armeabi-v7a/libmonochrome_test_dummy_partition.so, compress=False, alignment=4096
+apk_path=lib/armeabi-v7a/libmonochrome_vr_partition.so, compress=False, alignment=4096
 apk_path=assets/chrome_100_percent.pak, compress=False, alignment=4
+apk_path=assets/icudtl_extra.dat, compress=False, alignment=4
 apk_path=assets/locales/af.pak, compress=False, alignment=4
 apk_path=assets/locales/am.pak, compress=False, alignment=4
 apk_path=assets/locales/ar.pak, compress=False, alignment=4
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/PasswordGenerationIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/PasswordGenerationIntegrationTest.java
index 6c781a3..063ca81 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/PasswordGenerationIntegrationTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/PasswordGenerationIntegrationTest.java
@@ -33,7 +33,6 @@
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
 import org.chromium.chrome.browser.sync.SyncTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.components.browser_ui.modaldialog.AppModalPresenter;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.DOMUtils;
@@ -53,10 +52,6 @@
     @Rule
     public SyncTestRule mSyncTestRule = new SyncTestRule();
 
-    @Rule
-    public final ChromeTabbedActivityTestRule mActivityTestRule =
-            new ChromeTabbedActivityTestRule();
-
     private static final String PASSWORD_NODE_ID = "password_field";
     private static final String PASSWORD_NODE_ID_MANUAL = "password_field_manual";
     private static final String SUBMIT_NODE_ID = "input_submit_button";
@@ -67,7 +62,7 @@
     private static final String ELIGIBLE_FOR_GENERATION = "1";
     private static final String INFOBAR_MESSAGE = "Password saved";
 
-    private final ManualFillingTestHelper mHelper = new ManualFillingTestHelper(mActivityTestRule);
+    private final ManualFillingTestHelper mHelper = new ManualFillingTestHelper(mSyncTestRule);
 
     @Before
     public void setUp() throws InterruptedException {
@@ -196,7 +191,7 @@
     private void waitForGenerationDialog() {
         waitForModalDialogPresenter();
         ModalDialogManager manager = TestThreadUtils.runOnUiThreadBlockingNoException(
-                mActivityTestRule.getActivity()::getModalDialogManager);
+                mSyncTestRule.getActivity()::getModalDialogManager);
         Window window = ((AppModalPresenter) manager.getCurrentPresenterForTest()).getWindow();
         mHelper.waitForViewOnRoot(
                 window.getDecorView().getRootView(), withId(password_generation_dialog));
@@ -204,7 +199,7 @@
 
     private void waitForModalDialogPresenter() {
         CriteriaHelper.pollUiThread(()
-                                            -> mActivityTestRule.getActivity()
+                                            -> mSyncTestRule.getActivity()
                                                        .getModalDialogManager()
                                                        .getCurrentPresenterForTest()
                         != null);
@@ -212,9 +207,8 @@
 
     private void assertNoInfobarsAreShown() {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            Assert.assertFalse(
-                    InfoBarContainer.from(mActivityTestRule.getActivity().getActivityTab())
-                            .hasInfoBars());
+            Assert.assertFalse(InfoBarContainer.from(mSyncTestRule.getActivity().getActivityTab())
+                                       .hasInfoBars());
         });
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivitySessionTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivitySessionTracker.java
index 8d1124e..e475645 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivitySessionTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivitySessionTracker.java
@@ -140,7 +140,7 @@
         updateAcceptLanguages();
         mVariationsSession.start();
         mPowerBroadcastReceiver.onForegroundSessionStart();
-        ChimeSession.register();
+        ChimeSession.start();
 
         // Track the ratio of Chrome startups that are caused by notification clicks.
         // TODO(johnme): Add other reasons (and switch to recordEnumeratedHistogram).
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
index 984ebce..7e75ea0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
@@ -65,7 +65,6 @@
 import org.chromium.chrome.browser.toolbar.top.ToolbarActionModeCallback;
 import org.chromium.chrome.browser.toolbar.top.ToolbarLayout;
 import org.chromium.chrome.browser.toolbar.top.ToolbarPhone;
-import org.chromium.chrome.browser.ui.native_page.NativePage;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.browser_ui.widget.TintedDrawable;
 import org.chromium.components.page_info.PageInfoController;
@@ -868,12 +867,6 @@
                 @OmniboxFocusReason int reason) {}
 
         @Override
-        public boolean isCurrentPage(NativePage nativePage) {
-            return false;
-        }
-
-        @Nullable
-        @Override
         public VoiceRecognitionHandler getVoiceRecognitionHandler() {
             return null;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
index 00dca72..4d76cb02 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
@@ -255,8 +255,8 @@
                 if (sObserver != null) sObserver.onFlowIsKnown(mFreProperties);
                 recordFreProgressHistogram(mFreProgressStates.get(0));
                 long inflationCompletion = SystemClock.elapsedRealtime();
-                RecordHistogram.recordTimesHistogram(
-                        "MobileFre.FromLaunch.FirstFragmentInflated", inflationCompletion);
+                RecordHistogram.recordTimesHistogram("MobileFre.FromLaunch.FirstFragmentInflatedV2",
+                        inflationCompletion - mIntentCreationElapsedRealtimeMs);
                 mFirstRunAppRestrictionInfo.getCompletionElapsedRealtimeMs(
                         restrictionsCompletion -> {
                             if (restrictionsCompletion > inflationCompletion) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java
index 86ef470..8b3f231 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java
@@ -6,9 +6,7 @@
 
 import android.content.Context;
 import android.graphics.Rect;
-import android.net.Uri;
 
-import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.supplier.DestroyableObservableSupplier;
@@ -32,14 +30,11 @@
 import org.chromium.chrome.browser.tab.state.CriticalPersistedTabData;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.ui.native_page.NativePage;
+import org.chromium.chrome.browser.ui.native_page.NativePage.NativePageType;
 import org.chromium.chrome.browser.ui.native_page.NativePageHost;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
-import org.chromium.components.embedder_support.util.UrlConstants;
 import org.chromium.content_public.browser.LoadUrlParams;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
 /**
  * Creates NativePage objects to show chrome-native:// URLs using the native Android view system.
  */
@@ -122,53 +117,6 @@
         }
     }
 
-    @IntDef({NativePageType.NONE, NativePageType.CANDIDATE, NativePageType.NTP,
-            NativePageType.BOOKMARKS, NativePageType.RECENT_TABS, NativePageType.DOWNLOADS,
-            NativePageType.HISTORY, NativePageType.EXPLORE})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface NativePageType {
-        int NONE = 0;
-        int CANDIDATE = 1;
-        int NTP = 2;
-        int BOOKMARKS = 3;
-        int RECENT_TABS = 4;
-        int DOWNLOADS = 5;
-        int HISTORY = 6;
-        int EXPLORE = 7;
-    }
-
-    private static @NativePageType int nativePageType(
-            String url, NativePage candidatePage, boolean isIncognito) {
-        if (url == null) return NativePageType.NONE;
-
-        Uri uri = Uri.parse(url);
-        if (!UrlConstants.CHROME_NATIVE_SCHEME.equals(uri.getScheme())
-                && !UrlConstants.CHROME_SCHEME.equals(uri.getScheme())) {
-            return NativePageType.NONE;
-        }
-
-        String host = uri.getHost();
-        if (candidatePage != null && candidatePage.getHost().equals(host)) {
-            return NativePageType.CANDIDATE;
-        }
-
-        if (UrlConstants.NTP_HOST.equals(host)) {
-            return NativePageType.NTP;
-        } else if (UrlConstants.BOOKMARKS_HOST.equals(host)) {
-            return NativePageType.BOOKMARKS;
-        } else if (UrlConstants.DOWNLOADS_HOST.equals(host)) {
-            return NativePageType.DOWNLOADS;
-        } else if (UrlConstants.HISTORY_HOST.equals(host)) {
-            return NativePageType.HISTORY;
-        } else if (UrlConstants.RECENT_TABS_HOST.equals(host) && !isIncognito) {
-            return NativePageType.RECENT_TABS;
-        } else if (ExploreSitesPage.isExploreSitesHost(host)) {
-            return NativePageType.EXPLORE;
-        } else {
-            return NativePageType.NONE;
-        }
-    }
-
     /**
      * Returns a NativePage for displaying the given URL if the URL is a valid chrome-native URL,
      * or null otherwise. If candidatePage is non-null and corresponds to the URL, it will be
@@ -188,7 +136,7 @@
             String url, NativePage candidatePage, Tab tab, boolean isIncognito) {
         NativePage page;
 
-        switch (nativePageType(url, candidatePage, isIncognito)) {
+        switch (NativePage.nativePageType(url, candidatePage, isIncognito)) {
             case NativePageType.NONE:
                 return null;
             case NativePageType.CANDIDATE:
@@ -222,14 +170,14 @@
 
     /**
      * Returns whether the URL would navigate to a native page.
-     *
+     * TODO(crbug.com/1127732): Use NativePage.isNativePageUrl directly.
      * @param url The URL to be checked.
      * @param isIncognito Whether the page will be displayed in incognito mode.
      * @return Whether the host and the scheme of the passed in URL matches one of the supported
      *         native pages.
      */
     public static boolean isNativePageUrl(String url, boolean isIncognito) {
-        return nativePageType(url, null, isIncognito) != NativePageType.NONE;
+        return NativePage.isNativePageUrl(url, isIncognito);
     }
 
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/FakeboxDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/FakeboxDelegate.java
index 0ef3cc8..b11e4b6a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/FakeboxDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/FakeboxDelegate.java
@@ -9,7 +9,6 @@
 import org.chromium.chrome.browser.omnibox.OmniboxFocusReason;
 import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener;
 import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler;
-import org.chromium.chrome.browser.ui.native_page.NativePage;
 
 import java.util.List;
 
@@ -43,11 +42,9 @@
     boolean isUrlBarFocused();
 
     /**
-     * @return whether the provided native page is the one currently displayed to the user.
+     * Get the {@link VoiceRecognitionHandler}.
+     * @return the {@link VoiceRecognitionHandler}
      */
-    boolean isCurrentPage(NativePage nativePage);
-
-    /** Gets the {@link VoiceRecognitionHandler}. */
     @Nullable
     VoiceRecognitionHandler getVoiceRecognitionHandler();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index adc32d67..5d149db 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -200,7 +200,13 @@
         public boolean isCurrentPage() {
             if (mIsDestroyed) return false;
             if (mFakeboxDelegate == null) return false;
-            return mFakeboxDelegate.isCurrentPage(NewTabPage.this);
+            return getNewTabPageForCurrentTab() == NewTabPage.this;
+        }
+
+        private NewTabPage getNewTabPageForCurrentTab() {
+            Tab currentTab = mActivityTabProvider.get();
+            NativePage nativePage = currentTab != null ? currentTab.getNativePage() : null;
+            return (nativePage instanceof NewTabPage) ? (NewTabPage) nativePage : null;
         }
 
         @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
index fcf8c02..64ad69a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
@@ -22,7 +22,6 @@
 import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider;
 import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.chrome.browser.toolbar.top.ToolbarActionModeCallback;
-import org.chromium.chrome.browser.ui.native_page.NativePage;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 
@@ -235,11 +234,6 @@
         return mLocationBarLayout.isUrlBarFocused();
     }
 
-    @Override
-    public boolean isCurrentPage(NativePage nativePage) {
-        return mLocationBarLayout.isCurrentPage(nativePage);
-    }
-
     @Nullable
     @Override
     public VoiceRecognitionHandler getVoiceRecognitionHandler() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index d36750e..e6809c3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -73,7 +73,6 @@
 import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
 import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.chrome.browser.toolbar.top.ToolbarActionModeCallback;
-import org.chromium.chrome.browser.ui.native_page.NativePage;
 import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
 import org.chromium.chrome.browser.util.KeyNavigationUtil;
 import org.chromium.components.browser_ui.styles.ChromeColors;
@@ -675,12 +674,6 @@
     }
 
     @Override
-    public boolean isCurrentPage(NativePage nativePage) {
-        assert nativePage != null;
-        return nativePage == mToolbarDataProvider.getNewTabPageForCurrentTab();
-    }
-
-    @Override
     public VoiceRecognitionHandler getVoiceRecognitionHandler() {
         return mVoiceRecognitionHandler;
     }
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 58641f03..7c4722d 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
@@ -269,7 +269,7 @@
         }
 
         // On non-NTP pages, there will always be an icon when unfocused.
-        if (mToolbarDataProvider.getNewTabPageForCurrentTab() == null) return 0;
+        if (!mToolbarDataProvider.getNewTabPageDelegate().isCurrentlyVisible()) return 0;
 
         // This offset is only required when the focus animation is running.
         if (!hasFocus) return 0;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
index 4b62c4b..88ddd15 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
@@ -16,7 +16,6 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.download.DownloadUtils;
-import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.toolbar.top.ToolbarTablet;
 import org.chromium.components.browser_ui.widget.animation.CancelAwareAnimatorListener;
@@ -150,7 +149,7 @@
             mUrlFocusChangeAnimator = null;
         }
 
-        if (getToolbarDataProvider().getNewTabPageForCurrentTab() == null) {
+        if (getToolbarDataProvider().getNewTabPageDelegate().isCurrentlyVisible()) {
             finishUrlFocusChange(hasFocus);
             return;
         }
@@ -186,9 +185,8 @@
     @Override
     public void setUrlFocusChangeFraction(float fraction) {
         super.setUrlFocusChangeFraction(fraction);
-
-        NewTabPage ntp = getToolbarDataProvider().getNewTabPageForCurrentTab();
-        if (ntp != null) ntp.setUrlFocusChangeAnimationPercent(fraction);
+        getToolbarDataProvider().getNewTabPageDelegate().setUrlFocusChangeAnimationPercent(
+                fraction);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java
index 63026665..9f1634ce 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java
@@ -10,10 +10,10 @@
 import androidx.annotation.ColorRes;
 
 import org.chromium.base.library_loader.LibraryLoader;
-import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.omnibox.UrlBarData;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.toolbar.NewTabPageDelegate;
 import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.security_state.ConnectionSecurityLevel;
@@ -90,8 +90,8 @@
     }
 
     @Override
-    public NewTabPage getNewTabPageForCurrentTab() {
-        return null;
+    public NewTabPageDelegate getNewTabPageDelegate() {
+        return NewTabPageDelegate.EMPTY;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandler.java
index 8d0dc876..beb83f2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandler.java
@@ -125,7 +125,6 @@
      *         animating.
      */
     private boolean showScrimAfterAnimationCompletes() {
-        if (mToolbarDataProvider.getNewTabPageForCurrentTab() == null) return false;
-        return mToolbarDataProvider.getNewTabPageForCurrentTab().isLocationBarShownInNTP();
+        return mToolbarDataProvider.getNewTabPageDelegate().isLocationBarShown();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
index 9ce05a9a..2a032a4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
@@ -20,8 +20,6 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
 import org.chromium.chrome.browser.dom_distiller.DomDistillerTabUtils;
-import org.chromium.chrome.browser.native_page.NativePageFactory;
-import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
 import org.chromium.chrome.browser.omnibox.ChromeAutocompleteSchemeClassifier;
 import org.chromium.chrome.browser.omnibox.SearchEngineLogoUtils;
@@ -31,6 +29,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TrustedCdn;
+import org.chromium.chrome.browser.ui.native_page.NativePage;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
 import org.chromium.components.embedder_support.util.UrlConstants;
@@ -49,8 +48,9 @@
 /**
  * Provides a way of accessing toolbar data and state.
  */
-public class LocationBarModel implements ToolbarDataProvider, ToolbarCommonPropertiesModel {
+public class LocationBarModel implements ToolbarDataProvider {
     private final Context mContext;
+    private final NewTabPageDelegate mNtpDelegate;
 
     private Tab mTab;
     private int mPrimaryColor;
@@ -66,8 +66,9 @@
      * Default constructor for this class.
      * @param context The Context used for styling the toolbar visuals.
      */
-    public LocationBarModel(Context context) {
+    public LocationBarModel(Context context, NewTabPageDelegate newTabPageDelegate) {
         mContext = context;
+        mNtpDelegate = newTabPageDelegate;
         mPrimaryColor = ChromeColors.getDefaultThemeColor(context.getResources(), false);
     }
 
@@ -138,11 +139,8 @@
     }
 
     @Override
-    public NewTabPage getNewTabPageForCurrentTab() {
-        if (hasTab() && mTab.getNativePage() instanceof NewTabPage) {
-            return (NewTabPage) mTab.getNativePage();
-        }
-        return null;
+    public NewTabPageDelegate getNewTabPageDelegate() {
+        return mNtpDelegate;
     }
 
     @Override
@@ -150,7 +148,7 @@
         if (!hasTab()) return UrlBarData.EMPTY;
 
         String url = getCurrentUrl();
-        if (NativePageFactory.isNativePageUrl(url, isIncognito()) || UrlUtilities.isNTPUrl(url)) {
+        if (NativePage.isNativePageUrl(url, isIncognito()) || UrlUtilities.isNTPUrl(url)) {
             return UrlBarData.EMPTY;
         }
 
@@ -421,7 +419,7 @@
 
         boolean skipIconForNeutralState =
                 !SearchEngineLogoUtils.shouldShowSearchEngineLogo(isIncognito())
-                || getNewTabPageForCurrentTab() != null;
+                || mNtpDelegate.isCurrentlyVisible();
 
         return SecurityStatusIcon.getSecurityIconResource(securityLevel,
                 SecurityStateModel.shouldShowDangerTriangleForWarningLevel(), isSmallDevice,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/NewTabPageDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/NewTabPageDelegate.java
new file mode 100644
index 0000000..aff1e163
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/NewTabPageDelegate.java
@@ -0,0 +1,102 @@
+// 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.
+
+package org.chromium.chrome.browser.toolbar;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import org.chromium.base.Callback;
+
+/**
+ * Delegate that provides the toolbar with the info of the NTP for the current tab.
+ * TODO(crbug.com/1127732): Consider moving this out of toolbar/ into
+ *     its own target for omnibox as well.
+ */
+public interface NewTabPageDelegate {
+    /**
+     * @return {@code true} if the NewTabPage is currently visible.
+     */
+    default boolean isCurrentlyVisible() {
+        return false;
+    }
+
+    /**
+     * @return Whether the location bar is shown in the NTP.
+     */
+    default boolean isLocationBarShown() {
+        return false;
+    }
+
+    /**
+     * @return {@code true} if we're transitioning away from showing the location bar.
+     */
+    default boolean transitioningAwayFromLocationBar() {
+        return false;
+    }
+
+    /**
+     * Set the listener for NTP to handle the scroll event.
+     * @param scrollCallback Callback to be invoked when the event occurs.
+     */
+    default void setSearchBoxScrollListener(@Nullable Callback<Float> scrollCallback) {}
+
+    /**
+     * Get the bounds of the search box in relation to the top level NewTabPage view.
+     *
+     * @param bounds The current drawing location of the search box.
+     * @param translation The translation applied to the search box by the parent view hierarchy up
+     *                    to the NewTabPage view.
+     */
+    default void getSearchBoxBounds(Rect bounds, Point translation) {}
+
+    /**
+     * Updates the opacity of the search box when scrolling.
+     *
+     * @param alpha opacity (alpha) value to use.
+     */
+    default void setSearchBoxAlpha(float alpha) {}
+
+    /**
+     * Updates the opacity of the search provider logo when scrolling.
+     *
+     * @param alpha opacity (alpha) value to use.
+     */
+    default void setSearchProviderLogoAlpha(float alpha) {}
+
+    /**
+     * Set the search box background drawable.
+     *
+     * @param drawable The search box background.
+     */
+    default void setSearchBoxBackground(Drawable drawable) {}
+
+    /**
+     * Specifies the percentage the URL is focused during an animation.  1.0 specifies that the URL
+     * bar has focus and has completed the focus animation.  0 is when the URL bar is does not have
+     * any focus.
+     *
+     * @param percent The percentage of the URL bar focus animation.
+     */
+    default void setUrlFocusChangeAnimationPercent(float fraction) {}
+
+    /**
+     * Pass the motion event to NewTabPage object.
+     *
+     * @see {@link View#dispatchTouchEvent(MotionEvent)}
+     */
+    default boolean dispatchTouchEvent(MotionEvent ev) {
+        return false;
+    }
+
+    /**
+     * Empty implementation of NewTabDelegate. Used for a default before initialization.
+     */
+    public static final NewTabPageDelegate EMPTY = new NewTabPageDelegate() {};
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarCommonPropertiesModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarCommonPropertiesModel.java
index 1134f02..eb710e6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarCommonPropertiesModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarCommonPropertiesModel.java
@@ -7,8 +7,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.chromium.chrome.browser.ntp.NewTabPage;
-
 /**
  * Defines an interface that provides common properties to toolbar and omnibox classes.
  */
@@ -20,9 +18,10 @@
     String getCurrentUrl();
 
     /**
-     * @return The NewTabPage shown for the current Tab or null if one is not being shown.
+     * @return a delegate providing the info for the NTP of the current tab.
      */
-    NewTabPage getNewTabPageForCurrentTab();
+    @NonNull
+    NewTabPageDelegate getNewTabPageDelegate();
 
     /**
      * @return Whether the toolbar is currently being displayed for incognito.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
index f374078d..aca67d4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
@@ -12,7 +12,6 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
 
-import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.omnibox.UrlBarData;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
@@ -50,12 +49,6 @@
     String getCurrentUrl();
 
     /**
-     * @return The NewTabPage shown for the current Tab or null if one is not being shown.
-     */
-    @Override
-    NewTabPage getNewTabPageForCurrentTab();
-
-    /**
      * @return Whether the toolbar is currently being displayed for incognito.
      */
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 1d9eafa..0ae6a12 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -7,9 +7,12 @@
 import android.content.ComponentCallbacks;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.text.TextUtils;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnClickListener;
@@ -56,8 +59,8 @@
 import org.chromium.chrome.browser.ntp.IncognitoNewTabPage;
 import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.omnibox.LocationBar;
-import org.chromium.chrome.browser.omnibox.OmniboxFocusReason;
 import org.chromium.chrome.browser.omnibox.LocationBarCoordinator;
+import org.chromium.chrome.browser.omnibox.OmniboxFocusReason;
 import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener;
 import org.chromium.chrome.browser.previews.Previews;
 import org.chromium.chrome.browser.previews.PreviewsAndroidBridge;
@@ -88,6 +91,7 @@
 import org.chromium.chrome.browser.toolbar.top.ToolbarControlContainer;
 import org.chromium.chrome.browser.toolbar.top.ToolbarLayout;
 import org.chromium.chrome.browser.toolbar.top.ToolbarPhone;
+import org.chromium.chrome.browser.toolbar.top.ToolbarTablet;
 import org.chromium.chrome.browser.toolbar.top.TopToolbarCoordinator;
 import org.chromium.chrome.browser.toolbar.top.ViewShiftingActionBarDelegate;
 import org.chromium.chrome.browser.ui.TabObscuringHandler;
@@ -250,13 +254,16 @@
         mActivity = activity;
         mBrowserControlsSizer = controlsSizer;
         mFullscreenManager = fullscreenManager;
-        mActionBarDelegate = new ViewShiftingActionBarDelegate(activity, controlContainer);
+        mActionBarDelegate = new ViewShiftingActionBarDelegate(activity.getSupportActionBar(),
+                controlContainer, activity.findViewById(R.id.action_bar_black_background));
         mShareDelegateSupplier = shareDelegateSupplier;
         mCanAnimateNativeBrowserControls = canAnimateNativeBrowserControls;
         mScrimCoordinator = scrimCoordinator;
         mTabModelSelectorSupplier = tabModelSelectorSupplier;
 
-        mLocationBarModel = new LocationBarModel(activity);
+        ToolbarLayout toolbarLayout = mActivity.findViewById(R.id.toolbar);
+        NewTabPageDelegate ntpDelegate = createNewTabPageDelegate(toolbarLayout);
+        mLocationBarModel = new LocationBarModel(activity, ntpDelegate);
         mControlContainer = controlContainer;
         assert mControlContainer != null;
 
@@ -312,7 +319,6 @@
         ThemeColorProvider browsingModeThemeColorProvider =
                 mActivity.isTablet() ? mAppThemeColorProvider : mTabThemeColorProvider;
         ThemeColorProvider overviewModeThemeColorProvider = mAppThemeColorProvider;
-        ToolbarLayout toolbarLayout = mActivity.findViewById(R.id.toolbar);
 
         mMenuButtonCoordinator = new MenuButtonCoordinator(appMenuCoordinatorSupplier,
                 mControlsVisibilityDelegate, mActivity,
@@ -381,7 +387,7 @@
                 if (tab == null) return;
 
                 refreshSelectedTab(tab);
-                mToolbar.onTabOrModelChanged();
+                onTabOrModelChanged();
             }
 
             @Override
@@ -437,7 +443,7 @@
             @Override
             public void onContentChanged(Tab tab) {
                 if (tab.isNativePage()) TabThemeColorHelper.get(tab).updateIfNeeded(false);
-                mToolbar.onTabContentViewChanged();
+                notifyTabLoadingNtp();
                 if (shouldShowCursorInLocationBar()) {
                     mLocationBar.showUrlBarCursorWithoutFocusAnimations();
                 }
@@ -453,12 +459,12 @@
 
             @Override
             public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) {
-                NewTabPage ntp = mLocationBarModel.getNewTabPageForCurrentTab();
+                NewTabPage ntp = getNewTabPageForCurrentTab();
                 if (ntp == null) return;
                 if (!UrlUtilities.isNTPUrl(params.getUrl())
                         && loadType != TabLoadStatus.PAGE_LOAD_FAILED) {
                     ntp.setUrlFocusAnimationsDisabled(true);
-                    mToolbar.onTabOrModelChanged();
+                    onTabOrModelChanged();
                 }
             }
 
@@ -511,11 +517,11 @@
                 // location bar animations.
                 if (navigation.errorCode() != NetError.OK && navigation.isInMainFrame()
                         && !hasPendingNonNtpNavigation(tab)) {
-                    NewTabPage ntp = mLocationBarModel.getNewTabPageForCurrentTab();
+                    NewTabPage ntp = getNewTabPageForCurrentTab();
                     if (ntp == null) return;
 
                     ntp.setUrlFocusAnimationsDisabled(false);
-                    mToolbar.onTabOrModelChanged();
+                    onTabOrModelChanged();
                 }
             }
 
@@ -655,6 +661,7 @@
             MenuButtonCoordinator startSurfaceMenuButtonCoordinator, Invalidator invalidator,
             IdentityDiscController identityDiscController,
             OneshotSupplier<StartSurface> startSurfaceSupplier) {
+        // clang-format off
         TopToolbarCoordinator toolbar = new TopToolbarCoordinator(controlContainer, toolbarLayout,
                 mLocationBarModel, mToolbarTabController,
                 new UserEducationHelper(mActivity, mHandler, TrackerFactory::getTrackerForProfile),
@@ -662,17 +669,16 @@
                 mAppThemeColorProvider, mMenuButtonCoordinator, startSurfaceMenuButtonCoordinator,
                 mMenuButtonCoordinator.getMenuButtonHelperSupplier(), mTabModelSelectorSupplier,
                 mHomeButtonVisibilitySupplier, mIdentityDiscStateSupplier,
-                (client)
-                        -> {
+                (client) -> {
                     if (invalidator != null) {
                         invalidator.invalidate(client);
                     } else {
                         client.run();
                     }
                 },
-                ()
-                        -> identityDiscController.getForStartSurface(mStartSurfaceState),
+                () -> identityDiscController.getForStartSurface(mStartSurfaceState),
                 startSurfaceSupplier);
+        // clang-format on
         mHomepageStateListener =
                 () -> mHomeButtonVisibilitySupplier.set(HomepageManager.isHomepageEnabled());
         HomepageManager.getInstance().addListener(mHomepageStateListener);
@@ -684,6 +690,119 @@
         return toolbar;
     }
 
+    // Base abstract implementation of NewTabPageDelegate for phone/table toolbar layout.
+    private abstract class ToolbarNtpDelegate implements NewTabPageDelegate {
+        protected NewTabPage mVisibleNtp;
+
+        @Override
+        public boolean isCurrentlyVisible() {
+            return mVisibleNtp != null;
+        }
+
+        @Override
+        public boolean dispatchTouchEvent(MotionEvent ev) {
+            assert mVisibleNtp != null;
+            // No null check -- the toolbar should not be moved if we are not on an NTP.
+            return mVisibleNtp.getView().dispatchTouchEvent(ev);
+        }
+
+        @Override
+        public boolean isLocationBarShown() {
+            NewTabPage ntp = getNewTabPageForCurrentTab();
+            return ntp != null && ntp.isLocationBarShownInNTP();
+        }
+
+        @Override
+        public boolean transitioningAwayFromLocationBar() {
+            return isCurrentlyVisible() && mVisibleNtp.isLocationBarShownInNTP()
+                    && !isLocationBarShown();
+        }
+
+        @Override
+        public void setSearchBoxScrollListener(Callback<Float> scrollCallback) {
+            NewTabPage newVisibleNtp = getNewTabPageForCurrentTab();
+            if (mVisibleNtp == newVisibleNtp) return;
+            if (mVisibleNtp != null) mVisibleNtp.setSearchBoxScrollListener(null);
+            mVisibleNtp = newVisibleNtp;
+            if (mVisibleNtp != null && shouldUpdateListener()) {
+                mVisibleNtp.setSearchBoxScrollListener(
+                        (fraction) -> scrollCallback.onResult(fraction));
+            }
+        }
+
+        // Boolean predicate that tells if the NewTabPage.OnSearchBoxScrollListener
+        // should be updated or not
+        protected abstract boolean shouldUpdateListener();
+
+        @Override
+        public void getSearchBoxBounds(Rect bounds, Point translation) {
+            assert getNewTabPageForCurrentTab() != null;
+            getNewTabPageForCurrentTab().getSearchBoxBounds(bounds, translation);
+        }
+
+        @Override
+        public void setSearchBoxBackground(Drawable drawable) {
+            assert getNewTabPageForCurrentTab() != null;
+            getNewTabPageForCurrentTab().setSearchBoxBackground(drawable);
+        }
+
+        @Override
+        public void setSearchBoxAlpha(float alpha) {
+            assert getNewTabPageForCurrentTab() != null;
+            getNewTabPageForCurrentTab().setSearchBoxAlpha(alpha);
+        }
+
+        @Override
+        public void setSearchProviderLogoAlpha(float alpha) {
+            assert getNewTabPageForCurrentTab() != null;
+            getNewTabPageForCurrentTab().setSearchProviderLogoAlpha(alpha);
+        }
+
+        @Override
+        public void setUrlFocusChangeAnimationPercent(float fraction) {
+            NewTabPage ntp = getNewTabPageForCurrentTab();
+            if (ntp != null) ntp.setUrlFocusChangeAnimationPercent(fraction);
+        }
+    }
+
+    private NewTabPageDelegate createNewTabPageDelegate(ToolbarLayout toolbarLayout) {
+        if (toolbarLayout instanceof ToolbarPhone) {
+            return new ToolbarNtpDelegate() {
+                @Override
+                protected boolean shouldUpdateListener() {
+                    return mVisibleNtp.isLocationBarShownInNTP();
+                }
+            };
+        } else if (toolbarLayout instanceof ToolbarTablet) {
+            return new ToolbarNtpDelegate() {
+                @Override
+                protected boolean shouldUpdateListener() {
+                    return true;
+                }
+            };
+        }
+        return NewTabPageDelegate.EMPTY;
+    }
+
+    private void onTabOrModelChanged() {
+        notifyTabLoadingNtp();
+        mLocationBar.updateMicButtonState();
+        mToolbar.onTabOrModelChanged();
+    }
+
+    private void notifyTabLoadingNtp() {
+        NewTabPage ntp = getNewTabPageForCurrentTab();
+        if (ntp != null) mLocationBar.onTabLoadingNTP(ntp);
+    }
+
+    private NewTabPage getNewTabPageForCurrentTab() {
+        if (mLocationBarModel.hasTab()) {
+            NativePage nativePage = mLocationBarModel.getTab().getNativePage();
+            if (nativePage instanceof NewTabPage) return (NewTabPage) nativePage;
+        }
+        return null;
+    }
+
     /**
      * Called when the contextual action bar's visibility has changed (i.e. the widget shown
      * when you can copy/paste text after long press).
@@ -1273,7 +1392,7 @@
                     tab != null ? TabThemeColorHelper.getColor(tab) : defaultPrimaryColor;
             onThemeColorChanged(primaryColor, false);
 
-            mToolbar.onTabOrModelChanged();
+            onTabOrModelChanged();
 
             if (tab != null) {
                 mToolbar.onNavigatedToDifferentPage();
@@ -1381,7 +1500,7 @@
      */
     @VisibleForTesting
     public HomeButton getHomeButtonForTesting() {
-        return mToolbar.getToolbarLayoutForTesting().getHomeButtonForTesting();
+        return mToolbar.getToolbarLayoutForTesting().getHomeButton();
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressMediator.java
index 5ccf5340..b634150 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressMediator.java
@@ -6,10 +6,10 @@
 
 import org.chromium.base.MathUtils;
 import org.chromium.chrome.browser.ActivityTabProvider;
-import org.chromium.chrome.browser.native_page.NativePageFactory;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.toolbar.load_progress.LoadProgressProperties.CompletionState;
+import org.chromium.chrome.browser.ui.native_page.NativePage;
 import org.chromium.chrome.features.start_surface.StartSurfaceConfiguration;
 import org.chromium.components.embedder_support.util.UrlUtilities;
 import org.chromium.content_public.browser.NavigationHandle;
@@ -38,8 +38,7 @@
                     return;
                 }
 
-                if (NativePageFactory.isNativePageUrl(
-                            navigation.getUrlString(), tab.isIncognito())) {
+                if (NativePage.isNativePageUrl(navigation.getUrlString(), tab.isIncognito())) {
                     finishLoadProgress(false);
                     return;
                 }
@@ -64,8 +63,7 @@
             @Override
             public void onLoadProgressChanged(Tab tab, float progress) {
                 if (UrlUtilities.isNTPUrl(tab.getUrlString())
-                        || NativePageFactory.isNativePageUrl(
-                                tab.getUrlString(), tab.isIncognito())) {
+                        || NativePage.isNativePageUrl(tab.getUrlString(), tab.isIncognito())) {
                     return;
                 }
 
@@ -122,7 +120,7 @@
         }
 
         if (tab.isLoading()) {
-            if (NativePageFactory.isNativePageUrl(tab.getUrlString(), tab.isIncognito())) {
+            if (NativePage.isNativePageUrl(tab.getUrlString(), tab.isIncognito())) {
                 finishLoadProgress(false);
             } else {
                 startLoadProgress();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
index 674e2be..db66f581 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -30,16 +30,16 @@
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
 import org.chromium.chrome.browser.compositor.overlays.toolbar.TopToolbarOverlayCoordinator;
 import org.chromium.chrome.browser.findinpage.FindToolbar;
-import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.omnibox.LocationBar;
-import org.chromium.chrome.browser.omnibox.OmniboxFocusReason;
 import org.chromium.chrome.browser.omnibox.LocationBarCoordinator;
+import org.chromium.chrome.browser.omnibox.OmniboxFocusReason;
 import org.chromium.chrome.browser.omnibox.UrlBarData;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.toolbar.ButtonData;
 import org.chromium.chrome.browser.toolbar.HomeButton;
+import org.chromium.chrome.browser.toolbar.NewTabPageDelegate;
 import org.chromium.chrome.browser.toolbar.TabCountProvider;
 import org.chromium.chrome.browser.toolbar.ThemeColorProvider;
 import org.chromium.chrome.browser.toolbar.ThemeColorProvider.ThemeColorObserver;
@@ -278,8 +278,8 @@
             }
 
             @Override
-            public NewTabPage getNewTabPageForCurrentTab() {
-                return null;
+            public NewTabPageDelegate getNewTabPageDelegate() {
+                return NewTabPageDelegate.EMPTY;
             }
 
             @Override
@@ -556,14 +556,7 @@
      * tabs but no normal tabs will still allow you to select the normal model), this should
      * not guarantee that the model's current tab is non-null.
      */
-    void onTabOrModelChanged() {
-        NewTabPage ntp = getToolbarDataProvider().getNewTabPageForCurrentTab();
-        if (ntp != null) {
-            getLocationBar().onTabLoadingNTP(ntp);
-        }
-
-        getLocationBar().updateMicButtonState();
-    }
+    void onTabOrModelChanged() {}
 
     /**
      * For extending classes to override and carry out the changes related with the primary color
@@ -611,10 +604,7 @@
     /**
      * Triggered when the content view for the specified tab has changed.
      */
-    void onTabContentViewChanged() {
-        NewTabPage ntp = getToolbarDataProvider().getNewTabPageForCurrentTab();
-        if (ntp != null) getLocationBar().onTabLoadingNTP(ntp);
-    }
+    void onTabContentViewChanged() {}
 
     boolean isReadyForTextureCapture() {
         return true;
@@ -860,8 +850,7 @@
     /**
      * @return {@link HomeButton} this {@link ToolbarLayout} contains.
      */
-    @VisibleForTesting
-    public HomeButton getHomeButtonForTesting() {
+    public HomeButton getHomeButton() {
         return null;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
index 88a7a2a..13c0576 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -52,7 +52,6 @@
 import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.homepage.HomepageManager;
-import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.omnibox.LocationBar;
 import org.chromium.chrome.browser.omnibox.LocationBarCoordinator;
 import org.chromium.chrome.browser.omnibox.SearchEngineLogoUtils;
@@ -63,6 +62,7 @@
 import org.chromium.chrome.browser.toolbar.ButtonData;
 import org.chromium.chrome.browser.toolbar.HomeButton;
 import org.chromium.chrome.browser.toolbar.KeyboardNavigationListener;
+import org.chromium.chrome.browser.toolbar.NewTabPageDelegate;
 import org.chromium.chrome.browser.toolbar.TabCountProvider;
 import org.chromium.chrome.browser.toolbar.TabCountProvider.TabCountObserver;
 import org.chromium.chrome.browser.toolbar.TabSwitcherDrawable;
@@ -87,8 +87,7 @@
 /**
  * Phone specific toolbar implementation.
  */
-public class ToolbarPhone extends ToolbarLayout
-        implements OnClickListener, NewTabPage.OnSearchBoxScrollListener, TabCountObserver {
+public class ToolbarPhone extends ToolbarLayout implements OnClickListener, TabCountObserver {
     /** The amount of time transitioning from one theme color to another should take in ms. */
     public static final long THEME_COLOR_TRANSITION_DURATION = 250;
 
@@ -255,7 +254,6 @@
 
     protected @VisualState int mVisualState = VisualState.NORMAL;
 
-    private NewTabPage mVisibleNewTabPage;
     private float mPreTextureCaptureAlpha = 1f;
     private int mPreTextureCaptureVisibility;
     private boolean mIsOverlayTabStackDrawableLight;
@@ -505,10 +503,7 @@
         // reached the top of the page yet.
         if (mNtpSearchBoxTranslation.y < 0
                 && mLocationBar.getPhoneCoordinator().getTranslationY() > 0) {
-            NewTabPage newTabPage = getToolbarDataProvider().getNewTabPageForCurrentTab();
-
-            // No null check -- the toolbar should not be moved if we are not on an NTP.
-            return newTabPage.getView().dispatchTouchEvent(ev);
+            return getToolbarDataProvider().getNewTabPageDelegate().dispatchTouchEvent(ev);
         }
 
         return super.onTouchEvent(ev);
@@ -789,9 +784,7 @@
         return super.verifyDrawable(who) || who == mActiveLocationBarBackground;
     }
 
-    // NewTabPage.OnSearchBoxScrollListener
-    @Override
-    public void onNtpScrollChanged(float scrollFraction) {
+    private void onNtpScrollChanged(float scrollFraction) {
         mNtpSearchBoxScrollFraction = scrollFraction;
         updateUrlExpansionFraction();
         updateUrlExpansionAnimation();
@@ -1013,11 +1006,8 @@
 
         Tab currentTab = getToolbarDataProvider().getTab();
         if (currentTab != null) {
-            NewTabPage ntp = getToolbarDataProvider().getNewTabPageForCurrentTab();
-            if (ntp != null) {
-                ntp.setUrlFocusChangeAnimationPercent(mUrlFocusChangeFraction);
-            }
-
+            getToolbarDataProvider().getNewTabPageDelegate().setUrlFocusChangeAnimationPercent(
+                    mUrlFocusChangeFraction);
             if (isLocationBarShownInNTP()
                     && !getToolbarDataProvider().isInOverviewAndShowingOmnibox()) {
                 updateNtpTransitionAnimation();
@@ -1154,8 +1144,8 @@
             mToolbarShadow.setAlpha(alpha);
         }
 
-        NewTabPage ntp = getToolbarDataProvider().getNewTabPageForCurrentTab();
-        ntp.getSearchBoxBounds(mNtpSearchBoxBounds, mNtpSearchBoxTranslation);
+        NewTabPageDelegate ntpDelegate = getToolbarDataProvider().getNewTabPageDelegate();
+        ntpDelegate.getSearchBoxBounds(mNtpSearchBoxBounds, mNtpSearchBoxTranslation);
         int locationBarTranslationY = Math.max(
                 0, (mNtpSearchBoxBounds.top - mLocationBar.getPhoneCoordinator().getTop()));
         mLocationBar.getPhoneCoordinator().setTranslationY(locationBarTranslationY);
@@ -1188,7 +1178,7 @@
         mLocationBar.getPhoneCoordinator().setAlpha(relativeAlpha);
 
         // The search box on the NTP is visible if our omnibox is invisible, and vice-versa.
-        ntp.setSearchBoxAlpha(1f - relativeAlpha);
+        ntpDelegate.setSearchBoxAlpha(1f - relativeAlpha);
         if (!mForceDrawLocationBarBackground) {
             if (mActiveLocationBarBackground instanceof NtpSearchBoxDrawable) {
                 ((NtpSearchBoxDrawable) mActiveLocationBarBackground).resetBoundsToLastNonToolbar();
@@ -1650,7 +1640,7 @@
     }
 
     @Override
-    public HomeButton getHomeButtonForTesting() {
+    public HomeButton getHomeButton() {
         return mHomeButton;
     }
 
@@ -2271,22 +2261,18 @@
     }
 
     private void updateNtpAnimationState() {
+        NewTabPageDelegate ntpDelegate = getToolbarDataProvider().getNewTabPageDelegate();
+
         // Store previous NTP scroll before calling reset as that clears this value.
-        boolean wasShowingNtp = mVisibleNewTabPage != null;
+        boolean wasShowingNtp = ntpDelegate.isCurrentlyVisible();
         float previousNtpScrollFraction = mNtpSearchBoxScrollFraction;
 
         resetNtpAnimationValues();
-        if (mVisibleNewTabPage != null) {
-            mVisibleNewTabPage.setSearchBoxScrollListener(null);
-            mVisibleNewTabPage = null;
-        }
-        mVisibleNewTabPage = getToolbarDataProvider().getNewTabPageForCurrentTab();
-        if (mVisibleNewTabPage != null && mVisibleNewTabPage.isLocationBarShownInNTP()) {
-            mVisibleNewTabPage.setSearchBoxScrollListener(this);
-
+        ntpDelegate.setSearchBoxScrollListener(this::onNtpScrollChanged);
+        if (ntpDelegate.isLocationBarShown()) {
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                 NtpSearchBoxDrawable ntpSearchBox = new NtpSearchBoxDrawable(getContext(), this);
-                mVisibleNewTabPage.setSearchBoxBackground(ntpSearchBox);
+                ntpDelegate.setSearchBoxBackground(ntpSearchBox);
                 mActiveLocationBarBackground = ntpSearchBox;
             }
 
@@ -2329,13 +2315,11 @@
     }
 
     private boolean isLocationBarShownInNTP() {
-        NewTabPage ntp = getToolbarDataProvider().getNewTabPageForCurrentTab();
-        return ntp != null && ntp.isLocationBarShownInNTP();
+        return getToolbarDataProvider().getNewTabPageDelegate().isLocationBarShown();
     }
 
     private boolean isLocationBarCurrentlyShown() {
-        NewTabPage ntp = getToolbarDataProvider().getNewTabPageForCurrentTab();
-        return ntp == null || !isLocationBarShownInNTP() || mUrlExpansionFraction > 0;
+        return !isLocationBarShownInNTP() || mUrlExpansionFraction > 0;
     }
 
     /**
@@ -2549,8 +2533,8 @@
             return;
         }
 
-        boolean transitioningAwayFromLocationBarInNTP = mVisibleNewTabPage != null
-                && mVisibleNewTabPage.isLocationBarShownInNTP() && !isLocationBarShownInNTP();
+        boolean transitioningAwayFromLocationBarInNTP =
+                getToolbarDataProvider().getNewTabPageDelegate().transitioningAwayFromLocationBar();
 
         if (mTabSwitcherState == STATIC_TAB && !mUrlFocusChangeInProgress && !urlHasFocus()
                 && !transitioningAwayFromLocationBarInNTP) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
index 91cd174..e1d3011 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
@@ -30,7 +30,6 @@
 import org.chromium.chrome.browser.NavigationPopup;
 import org.chromium.chrome.browser.download.DownloadUtils;
 import org.chromium.chrome.browser.homepage.HomepageManager;
-import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.omnibox.LocationBar;
 import org.chromium.chrome.browser.omnibox.LocationBarCoordinator;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
@@ -40,6 +39,7 @@
 import org.chromium.chrome.browser.toolbar.ButtonData;
 import org.chromium.chrome.browser.toolbar.HomeButton;
 import org.chromium.chrome.browser.toolbar.KeyboardNavigationListener;
+import org.chromium.chrome.browser.toolbar.NewTabPageDelegate;
 import org.chromium.chrome.browser.toolbar.TabCountProvider;
 import org.chromium.chrome.browser.toolbar.TabCountProvider.TabCountObserver;
 import org.chromium.chrome.browser.toolbar.ToolbarColors;
@@ -92,8 +92,6 @@
     private boolean mShouldAnimateButtonVisibilityChange;
     private AnimatorSet mButtonVisibilityAnimators;
 
-    private NewTabPage mVisibleNtp;
-
     /**
      * Constructs a ToolbarTablet object.
      * @param context The Context in which this View object is created.
@@ -411,24 +409,13 @@
      * Called when the currently visible New Tab Page changes.
      */
     private void updateNtp() {
-        NewTabPage newVisibleNtp = getToolbarDataProvider().getNewTabPageForCurrentTab();
-        if (mVisibleNtp == newVisibleNtp) return;
-
-        if (mVisibleNtp != null) {
-            mVisibleNtp.setSearchBoxScrollListener(null);
-        }
-        mVisibleNtp = newVisibleNtp;
-        if (mVisibleNtp != null) {
-            mVisibleNtp.setSearchBoxScrollListener(new NewTabPage.OnSearchBoxScrollListener() {
-                @Override
-                public void onNtpScrollChanged(float scrollFraction) {
-                    // Fade the search box out in the first 40% of the scrolling transition.
-                    float alpha = Math.max(1f - scrollFraction * 2.5f, 0f);
-                    mVisibleNtp.setSearchBoxAlpha(alpha);
-                    mVisibleNtp.setSearchProviderLogoAlpha(alpha);
-                }
-            });
-        }
+        NewTabPageDelegate ntpDelegate = getToolbarDataProvider().getNewTabPageDelegate();
+        ntpDelegate.setSearchBoxScrollListener((scrollFraction) -> {
+            // Fade the search box out in the first 40% of the scrolling transition.
+            float alpha = Math.max(1f - scrollFraction * 2.5f, 0f);
+            ntpDelegate.setSearchBoxAlpha(alpha);
+            ntpDelegate.setSearchProviderLogoAlpha(alpha);
+        });
     }
 
     @Override
@@ -612,7 +599,7 @@
     }
 
     @Override
-    public HomeButton getHomeButtonForTesting() {
+    public HomeButton getHomeButton() {
         return mHomeButton;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ViewShiftingActionBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ViewShiftingActionBarDelegate.java
index 40d8355..c0ffc4c9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ViewShiftingActionBarDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ViewShiftingActionBarDelegate.java
@@ -9,26 +9,29 @@
 
 import androidx.appcompat.app.ActionBar;
 
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.app.ChromeActivity;
-
 /**
  * An {@link ActionModeController.ActionBarDelegate} that shifts a view as the action bar appears.
  */
 public class ViewShiftingActionBarDelegate implements ActionModeController.ActionBarDelegate {
+    /** The action bar which this delegate works for. */
+    private final ActionBar mActionBar;
+
     /** The view that will be shifted as the action bar appears. */
     private final View mShiftingView;
 
-    /** A handle to a {@link ChromeActivity}. */
-    private final ChromeActivity mActivity;
+    /** Action bar background view. */
+    private final View mBackgroundView;
 
     /**
-     * @param activity A handle to the {@link ChromeActivity}.
+     * @param actionBar The {@link ActionBar} in use.
      * @param shiftingView The view that will shift when the action bar appears.
+     * @param backgroundView Background view for shadow effect.
      */
-    public ViewShiftingActionBarDelegate(ChromeActivity activity, View shiftingView) {
-        mActivity = activity;
+    public ViewShiftingActionBarDelegate(
+            ActionBar actionBar, View shiftingView, View backgroundView) {
+        mActionBar = actionBar;
         mShiftingView = shiftingView;
+        mBackgroundView = backgroundView;
     }
 
     @Override
@@ -48,13 +51,13 @@
 
     @Override
     public ActionBar getSupportActionBar() {
-        return mActivity.getSupportActionBar();
+        return mActionBar;
     }
 
     @Override
     public void setActionBarBackgroundVisibility(boolean visible) {
         int visibility = visible ? View.VISIBLE : View.GONE;
-        mActivity.findViewById(R.id.action_bar_black_background).setVisibility(visibility);
+        mBackgroundView.setVisibility(visibility);
         // TODO(tedchoc): Add support for changing the color based on the brand color.
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
index 9664522..13f4ea09 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
@@ -8,11 +8,9 @@
 import android.content.Context;
 import android.view.Surface;
 
-import dalvik.system.BaseDexClassLoader;
-
+import org.chromium.base.BundleUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
-import org.chromium.base.StrictModeContext;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
@@ -65,10 +63,7 @@
 
     @CalledByNative
     private static String getArCoreShimLibraryPath() {
-        try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
-            return ((BaseDexClassLoader) ContextUtils.getApplicationContext().getClassLoader())
-                    .findLibrary("arcore_sdk_c");
-        }
+        return BundleUtils.getNativeLibraryPath("arcore_sdk_c");
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoDismissTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoDismissTest.java
index d283142..c0ef9b4e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoDismissTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoDismissTest.java
@@ -32,7 +32,6 @@
 import org.chromium.chrome.browser.signin.SigninPromoController;
 import org.chromium.chrome.browser.sync.SyncTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.BookmarkTestRule;
 import org.chromium.chrome.test.util.BookmarkTestUtil;
 import org.chromium.chrome.test.util.ChromeTabUtils;
@@ -48,10 +47,6 @@
 
     private final BookmarkTestRule mBookmarkTestRule = new BookmarkTestRule();
 
-    @Rule
-    public final ChromeTabbedActivityTestRule mActivityTestRule =
-            new ChromeTabbedActivityTestRule();
-
     // As bookmarks need the fake AccountManagerFacade in SyncTestRule,
     // BookmarkTestRule should be initialized after and destroyed before the
     // SyncTestRule.
@@ -64,10 +59,9 @@
         BookmarkPromoHeader.setPrefPersonalizedSigninPromoDeclinedForTests(false);
         SigninPromoController.setSigninPromoImpressionsCountBookmarksForTests(0);
 
-        mActivityTestRule.startMainActivityOnBlankPage();
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             BookmarkModel bookmarkModel = new BookmarkModel(Profile.fromWebContents(
-                    mActivityTestRule.getActivity().getActivityTab().getWebContents()));
+                    mSyncTestRule.getActivity().getActivityTab().getWebContents()));
             bookmarkModel.loadFakePartnerBookmarkShimForTesting();
         });
         BookmarkTestUtil.waitForBookmarkModelLoaded();
@@ -82,20 +76,20 @@
     @Test
     @MediumTest
     public void testPromoNotShownAfterBeingDismissed() {
-        mBookmarkTestRule.showBookmarkManager(mActivityTestRule.getActivity());
+        mBookmarkTestRule.showBookmarkManager(mSyncTestRule.getActivity());
         onView(withId(R.id.signin_promo_view_container)).check(matches(isDisplayed()));
         onView(withId(R.id.signin_promo_close_button)).perform(click());
         onView(withId(R.id.signin_promo_view_container)).check(doesNotExist());
 
         closeBookmarkManager();
-        mBookmarkTestRule.showBookmarkManager(mActivityTestRule.getActivity());
+        mBookmarkTestRule.showBookmarkManager(mSyncTestRule.getActivity());
         onView(withId(R.id.signin_promo_view_container)).check(doesNotExist());
     }
 
     private void closeBookmarkManager() {
-        if (mActivityTestRule.getActivity().isTablet()) {
+        if (mSyncTestRule.getActivity().isTablet()) {
             ChromeTabbedActivity chromeTabbedActivity =
-                    (ChromeTabbedActivity) mActivityTestRule.getActivity();
+                    (ChromeTabbedActivity) mSyncTestRule.getActivity();
             ChromeTabUtils.closeCurrentTab(
                     InstrumentationRegistry.getInstrumentation(), chromeTabbedActivity);
         } else {
@@ -108,7 +102,7 @@
     public void testPromoNotExistWhenImpressionLimitReached() {
         SigninPromoController.setSigninPromoImpressionsCountBookmarksForTests(
                 SigninPromoController.getMaxImpressionsBookmarksForTests());
-        mBookmarkTestRule.showBookmarkManager(mActivityTestRule.getActivity());
+        mBookmarkTestRule.showBookmarkManager(mSyncTestRule.getActivity());
         onView(withId(R.id.signin_promo_view_container)).check(doesNotExist());
     }
 
@@ -116,7 +110,7 @@
     @MediumTest
     public void testPromoImpressionCountIncrementAfterDisplayingSigninPromo() {
         assertEquals(0, SigninPromoController.getSigninPromoImpressionsCountBookmarks());
-        mBookmarkTestRule.showBookmarkManager(mActivityTestRule.getActivity());
+        mBookmarkTestRule.showBookmarkManager(mSyncTestRule.getActivity());
         onView(withId(R.id.signin_promo_view_container)).check(matches(isDisplayed()));
         assertEquals(1, SigninPromoController.getSigninPromoImpressionsCountBookmarks());
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java
index e1c52869..01959a0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java
@@ -37,7 +37,6 @@
 import org.chromium.chrome.browser.signin.SigninActivityLauncherImpl;
 import org.chromium.chrome.browser.sync.SyncTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.BookmarkTestRule;
 import org.chromium.components.signin.metrics.SigninAccessPoint;
 
@@ -51,10 +50,6 @@
 
     private final BookmarkTestRule mBookmarkTestRule = new BookmarkTestRule();
 
-    @Rule
-    public final ChromeTabbedActivityTestRule mActivityTestRule =
-            new ChromeTabbedActivityTestRule();
-
     // As bookmarks need the fake AccountManagerFacade in SyncTestRule,
     // BookmarkTestRule should be initialized after and destroyed before the
     // SyncTestRule.
@@ -69,7 +64,6 @@
         BookmarkPromoHeader.forcePromoStateForTests(
                 BookmarkPromoHeader.PromoState.PROMO_SIGNIN_PERSONALIZED);
         SigninActivityLauncherImpl.setLauncherForTest(mMockSigninActivityLauncherImpl);
-        mActivityTestRule.startMainActivityOnBlankPage();
     }
 
     @After
@@ -120,7 +114,7 @@
     }
 
     private void showBookmarkManagerAndCheckSigninPromoIsDisplayed() {
-        mBookmarkTestRule.showBookmarkManager(mActivityTestRule.getActivity());
+        mBookmarkTestRule.showBookmarkManager(mSyncTestRule.getActivity());
         onView(withId(R.id.signin_promo_view_container)).check(matches(isDisplayed()));
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/SyncErrorInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/SyncErrorInfoBarTest.java
index 8371b914..86c2448 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/SyncErrorInfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/SyncErrorInfoBarTest.java
@@ -22,7 +22,6 @@
 import org.chromium.chrome.browser.sync.settings.SyncSettingsUtils;
 import org.chromium.chrome.browser.sync.settings.SyncSettingsUtils.SyncError;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
 import org.chromium.chrome.test.util.InfoBarUtil;
 import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
@@ -50,10 +49,6 @@
     };
 
     @Rule
-    public final ChromeTabbedActivityTestRule mActivityTestRule =
-            new ChromeTabbedActivityTestRule();
-
-    @Rule
     public final ChromeRenderTestRule mRenderTestRule =
             ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
@@ -61,58 +56,58 @@
     public void setUp() {
         deleteSyncErrorInfoBarShowTimePref();
         mFakeProfileSyncService = (FakeProfileSyncService) mSyncTestRule.getProfileSyncService();
-        mActivityTestRule.startMainActivityOnBlankPage();
+        mSyncTestRule.startMainActivityOnBlankPage();
     }
 
     @Test
     @LargeTest
     public void testSyncErrorInfoBarShownForAuthError() throws Exception {
         Assert.assertEquals("InfoBar should not be shown before signing in", 0,
-                mActivityTestRule.getInfoBars().size());
+                mSyncTestRule.getInfoBars().size());
         showSyncErrorInfoBarForAuthError();
-        Assert.assertEquals("InfoBar should be shown", 1, mActivityTestRule.getInfoBars().size());
+        Assert.assertEquals("InfoBar should be shown", 1, mSyncTestRule.getInfoBars().size());
 
         // Resolving the error should not show the infobar again.
         deleteSyncErrorInfoBarShowTimePref();
         mFakeProfileSyncService.setAuthError(GoogleServiceAuthError.State.NONE);
-        InfoBarUtil.waitUntilNoInfoBarsExist(mActivityTestRule.getInfoBars());
+        InfoBarUtil.waitUntilNoInfoBarsExist(mSyncTestRule.getInfoBars());
     }
 
     @Test
     @LargeTest
     public void testSyncErrorInfoBarShownForSyncSetupIncomplete() {
         Assert.assertEquals("InfoBar should not be shown before signing in", 0,
-                mActivityTestRule.getInfoBars().size());
+                mSyncTestRule.getInfoBars().size());
         showSyncErrorInfoBarForSyncSetupIncomplete();
-        Assert.assertEquals("InfoBar should be shown", 1, mActivityTestRule.getInfoBars().size());
+        Assert.assertEquals("InfoBar should be shown", 1, mSyncTestRule.getInfoBars().size());
 
         // Resolving the error should not show the infobar again.
         deleteSyncErrorInfoBarShowTimePref();
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             mFakeProfileSyncService.setFirstSetupComplete(SyncFirstSetupCompleteSource.BASIC_FLOW);
         });
-        InfoBarUtil.waitUntilNoInfoBarsExist(mActivityTestRule.getInfoBars());
+        InfoBarUtil.waitUntilNoInfoBarsExist(mSyncTestRule.getInfoBars());
     }
 
     @Test
     @LargeTest
     public void testSyncErrorInfoBarShownForPassphraseRequired() {
         Assert.assertEquals("InfoBar should not be shown before signing in", 0,
-                mActivityTestRule.getInfoBars().size());
+                mSyncTestRule.getInfoBars().size());
         showSyncErrorInfoBarForPassphraseRequired();
-        Assert.assertEquals("InfoBar should be shown", 1, mActivityTestRule.getInfoBars().size());
+        Assert.assertEquals("InfoBar should be shown", 1, mSyncTestRule.getInfoBars().size());
 
         // Resolving the error should not show the infobar again.
         deleteSyncErrorInfoBarShowTimePref();
         mFakeProfileSyncService.setPassphraseRequiredForPreferredDataTypes(false);
-        InfoBarUtil.waitUntilNoInfoBarsExist(mActivityTestRule.getInfoBars());
+        InfoBarUtil.waitUntilNoInfoBarsExist(mSyncTestRule.getInfoBars());
     }
 
     @Test
     @LargeTest
     public void testSyncErrorInfoBarNotShownWhenNoError() {
         Assert.assertEquals("InfoBar should not be shown before signing in", 0,
-                mActivityTestRule.getInfoBars().size());
+                mSyncTestRule.getInfoBars().size());
         mSyncTestRule.setUpAccountAndEnableSyncForTesting();
         SyncTestUtil.waitForSyncActive();
         mFakeProfileSyncService.setEngineInitialized(true);
@@ -130,7 +125,7 @@
         Assert.assertTrue(syncError != SyncError.SYNC_SETUP_INCOMPLETE);
 
         Assert.assertEquals("InfoBar should not be shown when there is no error", 0,
-                mActivityTestRule.getInfoBars().size());
+                mSyncTestRule.getInfoBars().size());
     }
 
     @Test
@@ -138,14 +133,14 @@
     public void testSyncErrorInfoBarIsNotShownBeforeMinimalIntervalPassed() {
         // Initiate auth error to show the infobar.
         Assert.assertEquals("InfoBar should not be shown before signing in", 0,
-                mActivityTestRule.getInfoBars().size());
+                mSyncTestRule.getInfoBars().size());
         showSyncErrorInfoBarForAuthError();
-        Assert.assertEquals("InfoBar should be shown", 1, mActivityTestRule.getInfoBars().size());
+        Assert.assertEquals("InfoBar should be shown", 1, mSyncTestRule.getInfoBars().size());
 
         // Create another new tab.
-        mActivityTestRule.loadUrlInNewTab(UrlConstants.CHROME_BLANK_URL);
+        mSyncTestRule.loadUrlInNewTab(UrlConstants.CHROME_BLANK_URL);
         Assert.assertEquals("InfoBar should not be shown again before minimum interval passed", 0,
-                mActivityTestRule.getInfoBars().size());
+                mSyncTestRule.getInfoBars().size());
 
         // Override the time of last seen infobar to minimum required time before current time.
         ContextUtils.getAppSharedPreferences()
@@ -154,9 +149,9 @@
                         System.currentTimeMillis()
                                 - SyncErrorInfoBar.MINIMAL_DURATION_BETWEEN_INFOBARS_MS)
                 .apply();
-        mActivityTestRule.loadUrlInNewTab(UrlConstants.CHROME_BLANK_URL);
+        mSyncTestRule.loadUrlInNewTab(UrlConstants.CHROME_BLANK_URL);
         Assert.assertEquals("InfoBar should be shown again after minimum interval passed", 1,
-                mActivityTestRule.getInfoBars().size());
+                mSyncTestRule.getInfoBars().size());
     }
 
     @Test
@@ -164,7 +159,7 @@
     @Feature("RenderTest")
     public void testSyncErrorInfoBarForAuthErrorView() throws IOException {
         showSyncErrorInfoBarForAuthError();
-        mRenderTestRule.render(mActivityTestRule.getInfoBarContainer().getContainerViewForTesting(),
+        mRenderTestRule.render(mSyncTestRule.getInfoBarContainer().getContainerViewForTesting(),
                 "sync_error_infobar_auth_error");
     }
 
@@ -173,7 +168,7 @@
     @Feature("RenderTest")
     public void testSyncErrorInfoBarForSyncSetupIncompleteView() throws IOException {
         showSyncErrorInfoBarForSyncSetupIncomplete();
-        mRenderTestRule.render(mActivityTestRule.getInfoBarContainer().getContainerViewForTesting(),
+        mRenderTestRule.render(mSyncTestRule.getInfoBarContainer().getContainerViewForTesting(),
                 "sync_error_infobar_sync_setup_incomplete");
     }
 
@@ -182,26 +177,26 @@
     @Feature("RenderTest")
     public void testSyncErrorInfoBarForPassphraseRequiredView() throws IOException {
         showSyncErrorInfoBarForPassphraseRequired();
-        mRenderTestRule.render(mActivityTestRule.getInfoBarContainer().getContainerViewForTesting(),
+        mRenderTestRule.render(mSyncTestRule.getInfoBarContainer().getContainerViewForTesting(),
                 "sync_error_infobar_passphrase_required");
     }
 
     private void showSyncErrorInfoBarForAuthError() {
         mSyncTestRule.setUpAccountAndEnableSyncForTesting();
         mFakeProfileSyncService.setAuthError(GoogleServiceAuthError.State.INVALID_GAIA_CREDENTIALS);
-        mActivityTestRule.loadUrlInNewTab(UrlConstants.CHROME_BLANK_URL);
+        mSyncTestRule.loadUrlInNewTab(UrlConstants.CHROME_BLANK_URL);
     }
 
     private void showSyncErrorInfoBarForPassphraseRequired() {
         mSyncTestRule.setUpAccountAndEnableSyncForTesting();
         mFakeProfileSyncService.setEngineInitialized(true);
         mFakeProfileSyncService.setPassphraseRequiredForPreferredDataTypes(true);
-        mActivityTestRule.loadUrlInNewTab(UrlConstants.CHROME_BLANK_URL);
+        mSyncTestRule.loadUrlInNewTab(UrlConstants.CHROME_BLANK_URL);
     }
 
     private void showSyncErrorInfoBarForSyncSetupIncomplete() {
         mSyncTestRule.setUpTestAccountAndSignInWithSyncSetupAsIncomplete();
-        mActivityTestRule.loadUrlInNewTab(UrlConstants.CHROME_BLANK_URL);
+        mSyncTestRule.loadUrlInNewTab(UrlConstants.CHROME_BLANK_URL);
     }
 
     private void deleteSyncErrorInfoBarShowTimePref() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
index 0fef330..72d8df7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
@@ -41,6 +41,7 @@
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.toolbar.LocationBarModel;
+import org.chromium.chrome.browser.toolbar.NewTabPageDelegate;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.OmniboxTestUtils;
@@ -85,7 +86,7 @@
         private Integer mSecurityLevel;
 
         public TestLocationBarModel() {
-            super(ContextUtils.getApplicationContext());
+            super(ContextUtils.getApplicationContext(), NewTabPageDelegate.EMPTY);
             initializeWithNative();
         }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java
index 6ef73cdcf5..e5e22dd9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java
@@ -38,8 +38,8 @@
 import org.chromium.base.test.util.Batch;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
-import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
+import org.chromium.chrome.browser.toolbar.NewTabPageDelegate;
 import org.chromium.chrome.browser.toolbar.ToolbarCommonPropertiesModel;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
@@ -61,7 +61,7 @@
     public TestRule mProcessor = new Features.JUnitProcessor();
 
     @Mock
-    NewTabPage mNewTabPage;
+    NewTabPageDelegate mNewTabPageDelegate;
     @Mock
     ToolbarCommonPropertiesModel mToolbarCommonPropertiesModel;
     @Mock
@@ -124,7 +124,8 @@
     @UiThreadTest
     public void searchEngineLogo_showGoogleLogo_hideAfterAnimationFinished() {
         setupSearchEngineLogoForTesting(true, false, false);
-        doReturn(mNewTabPage).when(mToolbarCommonPropertiesModel).getNewTabPageForCurrentTab();
+        doReturn(mNewTabPageDelegate).when(mToolbarCommonPropertiesModel).getNewTabPageDelegate();
+        doReturn(true).when(mNewTabPageDelegate).isCurrentlyVisible();
         doReturn("chrome://newtab").when(mToolbarCommonPropertiesModel).getCurrentUrl();
 
         mMediator.updateSearchEngineStatusIcon(true, true, TEST_SEARCH_URL);
@@ -171,7 +172,8 @@
         setupSearchEngineLogoForTesting(true, false, false);
         doReturn(false).when(mToolbarCommonPropertiesModel).isLoading();
         doReturn(UrlConstants.NTP_URL).when(mToolbarCommonPropertiesModel).getCurrentUrl();
-        doReturn(mNewTabPage).when(mToolbarCommonPropertiesModel).getNewTabPageForCurrentTab();
+        doReturn(mNewTabPageDelegate).when(mToolbarCommonPropertiesModel).getNewTabPageDelegate();
+        doReturn(true).when(mNewTabPageDelegate).isCurrentlyVisible();
 
         mMediator.setUrlHasFocus(false);
         mMediator.setShowIconsWhenUrlFocused(true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewRenderTest.java
index d569ccc9..5ff4e25 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewRenderTest.java
@@ -21,6 +21,7 @@
 import org.chromium.chrome.browser.omnibox.status.StatusProperties.StatusIconResource;
 import org.chromium.chrome.browser.omnibox.status.StatusView.StatusViewDelegate;
 import org.chromium.chrome.browser.toolbar.LocationBarModel;
+import org.chromium.chrome.browser.toolbar.NewTabPageDelegate;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
 import org.chromium.components.browser_ui.widget.CompositeTouchDelegate;
@@ -72,7 +73,7 @@
                                   .findViewById(org.chromium.chrome.R.id.location_bar_status);
             mStatusView.setCompositeTouchDelegate(new CompositeTouchDelegate(view));
             mStatusView.setToolbarCommonPropertiesModel(
-                    new LocationBarModel(mStatusView.getContext()));
+                    new LocationBarModel(mStatusView.getContext(), NewTabPageDelegate.EMPTY));
             mStatusModel = new PropertyModel.Builder(StatusProperties.ALL_KEYS).build();
             PropertyModelChangeProcessor.create(mStatusModel, mStatusView, new StatusViewBinder());
         });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewTest.java
index 675c2833..5f05faad 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewTest.java
@@ -36,6 +36,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.omnibox.status.StatusProperties.StatusIconResource;
 import org.chromium.chrome.browser.toolbar.LocationBarModel;
+import org.chromium.chrome.browser.toolbar.NewTabPageDelegate;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.components.browser_ui.widget.CompositeTouchDelegate;
@@ -76,7 +77,7 @@
             mStatusView.setDelegateForTesting(mStatusViewDelegate);
             mStatusView.setCompositeTouchDelegate(new CompositeTouchDelegate(view));
             mStatusView.setToolbarCommonPropertiesModel(
-                    new LocationBarModel(mStatusView.getContext()));
+                    new LocationBarModel(mStatusView.getContext(), NewTabPageDelegate.EMPTY));
             mStatusModel = new PropertyModel.Builder(StatusProperties.ALL_KEYS).build();
             mStatusMCP = PropertyModelChangeProcessor.create(
                     mStatusModel, mStatusView, new StatusViewBinder());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java
index 5a8ba75..9449dde 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandlerTest.java
@@ -33,7 +33,6 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.omnibox.UrlBarData;
 import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteController.OnSuggestionsReceivedListener;
@@ -47,6 +46,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.MockTab;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.toolbar.NewTabPageDelegate;
 import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
@@ -215,8 +215,8 @@
         }
 
         @Override
-        public NewTabPage getNewTabPageForCurrentTab() {
-            return null;
+        public NewTabPageDelegate getNewTabPageDelegate() {
+            return NewTabPageDelegate.EMPTY;
         }
 
         @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFragmentTest.java
index 34fac4e..d34e47d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFragmentTest.java
@@ -28,7 +28,6 @@
 import org.hamcrest.Matcher;
 import org.junit.After;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -42,7 +41,6 @@
 import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.browser.sync.SyncTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.ActivityUtils;
 import org.chromium.chrome.test.util.ApplicationTestUtils;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
@@ -67,20 +65,11 @@
     public final SyncTestRule mSyncTestRule = new SyncTestRule();
 
     @Rule
-    public final ChromeTabbedActivityTestRule mActivityTestRule =
-            new ChromeTabbedActivityTestRule();
-
-    @Rule
     public final ChromeRenderTestRule mRenderTestRule =
             ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     private SigninActivity mSigninActivity;
 
-    @Before
-    public void setUp() {
-        mActivityTestRule.startMainActivityOnBlankPage();
-    }
-
     @After
     public void tearDown() throws Exception {
         // Since SigninActivity is launched inside this test class, we need to
@@ -97,7 +86,7 @@
         mSigninActivity = ActivityUtils.waitForActivity(
                 InstrumentationRegistry.getInstrumentation(), SigninActivity.class, () -> {
                     SigninActivityLauncherImpl.get().launchActivityForPromoAddAccountFlow(
-                            mActivityTestRule.getActivity(), SigninAccessPoint.BOOKMARK_MANAGER);
+                            mSyncTestRule.getActivity(), SigninAccessPoint.BOOKMARK_MANAGER);
                 });
         mRenderTestRule.render(mSigninActivity.findViewById(R.id.fragment_container),
                 "signin_fragment_new_account");
@@ -112,7 +101,7 @@
         mSigninActivity = ActivityUtils.waitForActivity(
                 InstrumentationRegistry.getInstrumentation(), SigninActivity.class, () -> {
                     SigninActivityLauncherImpl.get().launchActivityForPromoChooseAccountFlow(
-                            mActivityTestRule.getActivity(), SigninAccessPoint.BOOKMARK_MANAGER,
+                            mSyncTestRule.getActivity(), SigninAccessPoint.BOOKMARK_MANAGER,
                             account.name);
                 });
         mRenderTestRule.render(mSigninActivity.findViewById(R.id.fragment_container),
@@ -129,7 +118,7 @@
         mSigninActivity = ActivityUtils.waitForActivity(
                 InstrumentationRegistry.getInstrumentation(), SigninActivity.class, () -> {
                     SigninActivityLauncherImpl.get().launchActivityForPromoChooseAccountFlow(
-                            mActivityTestRule.getActivity(), SigninAccessPoint.BOOKMARK_MANAGER,
+                            mSyncTestRule.getActivity(), SigninAccessPoint.BOOKMARK_MANAGER,
                             secondAccountName);
                 });
         mRenderTestRule.render(mSigninActivity.findViewById(R.id.fragment_container),
@@ -144,7 +133,7 @@
         mSigninActivity = ActivityUtils.waitForActivity(
                 InstrumentationRegistry.getInstrumentation(), SigninActivity.class, () -> {
                     SigninActivityLauncherImpl.get().launchActivityForPromoDefaultFlow(
-                            mActivityTestRule.getActivity(), SigninAccessPoint.BOOKMARK_MANAGER,
+                            mSyncTestRule.getActivity(), SigninAccessPoint.BOOKMARK_MANAGER,
                             account.name);
                 });
         mRenderTestRule.render(mSigninActivity.findViewById(R.id.fragment_container),
@@ -158,8 +147,7 @@
         mSigninActivity = ActivityUtils.waitForActivity(
                 InstrumentationRegistry.getInstrumentation(), SigninActivity.class, () -> {
                     SigninActivityLauncherImpl.get().launchActivityForPromoDefaultFlow(
-                            mActivityTestRule.getActivity(), SigninAccessPoint.SETTINGS,
-                            account.name);
+                            mSyncTestRule.getActivity(), SigninAccessPoint.SETTINGS, account.name);
                 });
         onView(withText(account.name)).check(matches(isDisplayed()));
         onView(withId(R.id.signin_details_description)).perform(clickOnClickableSpan());
@@ -183,7 +171,7 @@
         mSigninActivity = ActivityUtils.waitForActivity(
                 InstrumentationRegistry.getInstrumentation(), SigninActivity.class, () -> {
                     SigninActivityLauncherImpl.get().launchActivity(
-                            mActivityTestRule.getActivity(), SigninAccessPoint.SETTINGS);
+                            mSyncTestRule.getActivity(), SigninAccessPoint.SETTINGS);
                 });
         onView(withId(R.id.positive_button)).check(matches(withText(R.string.signin_add_account)));
         onView(withId(R.id.negative_button)).check(matches(withText(R.string.cancel)));
@@ -198,7 +186,7 @@
         mSigninActivity = ActivityUtils.waitForActivity(
                 InstrumentationRegistry.getInstrumentation(), SigninActivity.class, () -> {
                     SigninActivityLauncherImpl.get().launchActivityForPromoDefaultFlow(
-                            mActivityTestRule.getActivity(), SigninAccessPoint.BOOKMARK_MANAGER,
+                            mSyncTestRule.getActivity(), SigninAccessPoint.BOOKMARK_MANAGER,
                             defaultAccount.name);
                 });
         onView(withText(defaultAccount.name)).check(matches(isDisplayed())).perform(click());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java
index a7705dc..1ce8e88 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java
@@ -5,13 +5,15 @@
 package org.chromium.chrome.browser.sync;
 
 import android.accounts.Account;
-import android.content.ComponentName;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.test.InstrumentationRegistry;
 
-import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -22,16 +24,16 @@
 
 import org.chromium.base.CommandLine;
 import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.SyncFirstSetupCompleteSource;
-import org.chromium.chrome.browser.document.ChromeLauncherActivity;
+import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.browser.firstrun.FirstRunActivity;
 import org.chromium.chrome.browser.firstrun.FirstRunActivity.FirstRunActivityObserver;
 import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer;
 import org.chromium.chrome.browser.firstrun.FirstRunSignInProcessor;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.settings.SettingsActivity;
-import org.chromium.chrome.browser.sync.settings.SyncAndServicesSettings;
+import org.chromium.chrome.browser.sync.settings.AccountManagementFragment;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.ActivityUtils;
 import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
@@ -46,7 +48,51 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 public class FirstRunTest {
     @Rule
-    public SyncTestRule mSyncTestRule = new SyncTestRule();
+    public SyncTestRule mSyncTestRule = new SyncTestRule() {
+        @Override
+        public void startMainActivityForSyncTest() {
+            FirstRunActivity.setObserverForTest(mTestObserver);
+
+            // Starts up and waits for the FirstRunActivity to be ready.
+            // This isn't exactly what startMainActivity is supposed to be doing, but short of a
+            // refactoring of SyncTestBase to use something other than ChromeTabbedActivity,
+            // it's the only way to reuse the rest of the setup and initialization code inside of
+            // it.
+            final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+            final Context context = instrumentation.getTargetContext();
+
+            // Create an Intent that causes Chrome to run.
+            final Intent intent = new Intent(TEST_ACTION);
+            intent.setPackage(context.getPackageName());
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            // Start the FRE.
+            final ActivityMonitor freMonitor =
+                    new ActivityMonitor(FirstRunActivity.class.getName(), null, false);
+            instrumentation.addMonitor(freMonitor);
+            TestThreadUtils.runOnUiThreadBlocking(() -> {
+                FirstRunFlowSequencer.launch(context, intent, false /* requiresBroadcast */,
+                        false /* preferLightweightFre */);
+            });
+
+            // Wait for the FRE to be ready to use.
+            Activity activity =
+                    freMonitor.waitForActivityWithTimeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL);
+            instrumentation.removeMonitor(freMonitor);
+
+            mActivity = (FirstRunActivity) activity;
+
+            try {
+                mTestObserver.flowIsKnownCallback.waitForCallback(0);
+            } catch (TimeoutException e) {
+                Assert.fail();
+            }
+            CriteriaHelper.pollUiThread((() -> mActivity.isNativeSideIsInitializedForTest()),
+                    "native never initialized.");
+        }
+    };
+
+    private static final String TEST_ACTION = "com.artificial.package.TEST_ACTION";
 
     private static final class TestObserver implements FirstRunActivityObserver {
         public final CallbackHelper flowIsKnownCallback = new CallbackHelper();
@@ -79,29 +125,6 @@
     public void setUp() {
         Assert.assertFalse(
                 CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE));
-
-        FirstRunActivity.setObserverForTest(mTestObserver);
-
-        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setPackage(context.getPackageName());
-        intent.setComponent(new ComponentName(context, ChromeLauncherActivity.class));
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        Runnable activityTrigger = () -> TestThreadUtils.runOnUiThreadBlocking(() -> {
-            FirstRunFlowSequencer.launch(context, intent, false /* requiresBroadcast */,
-                    false /* preferLightweightFre */);
-        });
-        mActivity = ActivityUtils.waitForActivity(InstrumentationRegistry.getInstrumentation(),
-                FirstRunActivity.class, activityTrigger);
-
-        try {
-            mTestObserver.flowIsKnownCallback.waitForCallback(0);
-        } catch (TimeoutException e) {
-            Assert.fail();
-        }
-        CriteriaHelper.pollUiThread(
-                (() -> mActivity.isNativeSideIsInitializedForTest()), "native never initialized.");
     }
 
     @After
@@ -110,9 +133,12 @@
     }
 
     // Test that signing in through FirstRun signs in and starts sync.
+    /*
+     * @SmallTest
+     * @Feature({"Sync"})
+     */
     @Test
-    @LargeTest
-    @Feature({"Sync"})
+    @FlakyTest(message = "https://crbug.com/616456")
     public void testSignIn() {
         Account testAccount = mSyncTestRule.addTestAccount();
         Assert.assertNull(mSyncTestRule.getCurrentSignedInAccount());
@@ -125,9 +151,12 @@
 
     // Test that signing in and opening settings through FirstRun signs in and doesn't fully start
     // sync until the settings page is closed.
+    /*
+     * @SmallTest
+     * @Feature({"Sync"})
+     */
     @Test
-    @LargeTest
-    @Feature({"Sync"})
+    @FlakyTest(message = "https://crbug.com/616456")
     public void testSignInWithOpenSettings() {
         final Account testAccount = mSyncTestRule.addTestAccount();
         final SettingsActivity settingsActivity =
@@ -140,26 +169,20 @@
         Assert.assertFalse(SyncTestUtil.isSyncActive());
 
         // Close the settings fragment.
-        SyncAndServicesSettings fragment =
-                (SyncAndServicesSettings) settingsActivity.getMainFragment();
+        AccountManagementFragment fragment =
+                (AccountManagementFragment) settingsActivity.getMainFragment();
         Assert.assertNotNull(fragment);
         settingsActivity.getSupportFragmentManager().beginTransaction().remove(fragment).commit();
 
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            // First setup should not be marked as complete just by closing the fragment.
-            Assert.assertFalse(mSyncTestRule.getProfileSyncService().isFirstSetupComplete());
-
-            // Marking the first setup as complete should make sync active.
-            mSyncTestRule.getProfileSyncService().setFirstSetupComplete(
-                    SyncFirstSetupCompleteSource.BASIC_FLOW);
-        });
+        // Sync should immediately become active.
         Assert.assertTrue(SyncTestUtil.isSyncActive());
     }
 
     // Test that not signing in through FirstRun does not sign in sync.
     @Test
-    @LargeTest
+    @SmallTest
     @Feature({"Sync"})
+    @DisabledTest // https://crbug.com/901488
     public void testNoSignIn() {
         mSyncTestRule.addTestAccount();
         Assert.assertFalse(SyncTestUtil.isSyncRequested());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java
index b8ba660..16cb08c3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java
@@ -24,7 +24,6 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
 import org.chromium.components.sync.protocol.EntitySpecifics;
 import org.chromium.components.sync.protocol.SessionHeader;
@@ -52,10 +51,6 @@
     @Rule
     public SyncTestRule mSyncTestRule = new SyncTestRule();
 
-    @Rule
-    public final ChromeTabbedActivityTestRule mActivityTestRule =
-            new ChromeTabbedActivityTestRule();
-
     private static final String TAG = "OpenTabsTest";
 
     private static final String OPEN_TABS_TYPE = "Sessions";
@@ -101,8 +96,6 @@
         mSyncTestRule.setUpAccountAndEnableSyncForTesting();
         mClientName = getClientName();
         mSessionTagCounter = 0;
-
-        mActivityTestRule.startMainActivityOnBlankPage();
     }
 
     // Test syncing an open tab from client to server.
@@ -110,7 +103,7 @@
     @LargeTest
     @Feature({"Sync"})
     public void testUploadOpenTab() {
-        mActivityTestRule.loadUrl(URL);
+        mSyncTestRule.loadUrl(URL);
         waitForLocalTabsForClient(mClientName, URL);
         waitForServerTabs(URL);
     }
@@ -120,9 +113,9 @@
     @LargeTest
     @Feature({"Sync"})
     public void testUploadMultipleOpenTabs() {
-        mActivityTestRule.loadUrl(URL);
-        mActivityTestRule.loadUrlInNewTab(URL2);
-        mActivityTestRule.loadUrlInNewTab(URL3);
+        mSyncTestRule.loadUrl(URL);
+        mSyncTestRule.loadUrlInNewTab(URL2);
+        mSyncTestRule.loadUrlInNewTab(URL3);
         waitForLocalTabsForClient(mClientName, URL, URL2, URL3);
         waitForServerTabs(URL, URL2, URL3);
     }
@@ -132,14 +125,14 @@
     @LargeTest
     @Feature({"Sync"})
     public void testUploadAndCloseOpenTab() {
-        mActivityTestRule.loadUrl(URL);
+        mSyncTestRule.loadUrl(URL);
         // Can't have zero tabs, so we have to open two to test closing one.
-        mActivityTestRule.loadUrlInNewTab(URL2);
+        mSyncTestRule.loadUrlInNewTab(URL2);
         waitForLocalTabsForClient(mClientName, URL, URL2);
         waitForServerTabs(URL, URL2);
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            TabModelSelector selector = mActivityTestRule.getActivity().getTabModelSelector();
+            TabModelSelector selector = mSyncTestRule.getActivity().getTabModelSelector();
             Assert.assertTrue(TabModelUtils.closeCurrentTab(selector.getCurrentModel()));
         });
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
index a35e3df0..8ec02719 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
@@ -16,17 +16,19 @@
 import androidx.preference.TwoStatePreference;
 
 import org.junit.Assert;
-import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
 import org.chromium.base.Promise;
+import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
-import org.chromium.chrome.browser.init.ProcessInitializationHandler;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.UnifiedConsentServiceBridge;
+import org.chromium.chrome.browser.uid.UniqueIdentificationGenerator;
 import org.chromium.chrome.browser.uid.UniqueIdentificationGeneratorFactory;
+import org.chromium.chrome.browser.uid.UuidBasedUniqueIdentificationGenerator;
+import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
 import org.chromium.chrome.test.util.browser.signin.SigninTestUtil;
 import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
@@ -50,7 +52,7 @@
 /**
  * TestRule for common functionality between sync tests.
  */
-public class SyncTestRule implements TestRule {
+public class SyncTestRule extends ChromeActivityTestRule<ChromeActivity> {
     private static final String TAG = "SyncTestBase";
 
     private static final String CLIENT_ID = "Client_ID";
@@ -140,7 +142,9 @@
         ProfileSyncService.resetForTests();
     }
 
-    public SyncTestRule() {}
+    public SyncTestRule() {
+        super(ChromeActivity.class);
+    }
 
     /**Getters for Test variables */
     public Context getTargetContext() {
@@ -159,6 +163,12 @@
         return mSyncContentResolver;
     }
 
+    public void startMainActivityForSyncTest() throws Exception {
+        // Start the activity by opening about:blank. This URL is ideal because it is not synced as
+        // a typed URL. If another URL is used, it could interfere with test data.
+        startMainActivityOnBlankPage();
+    }
+
     /**
      * Adds an account of default account name to AccountManagerFacade and waits for the seeding.
      */
@@ -305,7 +315,7 @@
 
     @Override
     public Statement apply(final Statement statement, final Description desc) {
-        return mAccountManagerTestRule.apply(new Statement() {
+        final Statement base = super.apply(new Statement() {
             @Override
             public void evaluate() throws Throwable {
                 mSyncContentResolver = new MockSyncContentResolverDelegate();
@@ -318,9 +328,6 @@
 
                 // Load native since the FakeServer needs it and possibly ProfileSyncService as well
                 // (depends on what fake is provided by |createProfileSyncService()|).
-                TestThreadUtils.runOnUiThreadBlocking(() -> {
-                    ProcessInitializationHandler.getInstance().initializePreNative();
-                });
                 NativeLibraryTestUtils.loadNativeLibraryAndInitBrowserProcess();
 
                 TestThreadUtils.runOnUiThreadBlocking(() -> {
@@ -336,13 +343,27 @@
                 });
 
                 UniqueIdentificationGeneratorFactory.registerGenerator(
-                        SyncController.GENERATOR_ID, salt -> CLIENT_ID, true);
+                        UuidBasedUniqueIdentificationGenerator.GENERATOR_ID,
+                        new UniqueIdentificationGenerator() {
+                            @Override
+                            public String getUniqueId(String salt) {
+                                return CLIENT_ID;
+                            }
+                        },
+                        true);
+
+                startMainActivityForSyncTest();
 
                 // Ensure SyncController is created.
                 TestThreadUtils.runOnUiThreadBlocking(() -> SyncController.get());
 
                 statement.evaluate();
-
+            }
+        }, desc);
+        return mAccountManagerTestRule.apply(new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                base.evaluate();
                 ruleTearDown();
             }
         }, desc);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java
index 415ada8..5471161 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java
@@ -21,7 +21,6 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
 import org.chromium.components.sync.ModelType;
 import org.chromium.components.sync.protocol.EntitySpecifics;
@@ -46,10 +45,6 @@
     @Rule
     public SyncTestRule mSyncTestRule = new SyncTestRule();
 
-    @Rule
-    public final ChromeTabbedActivityTestRule mActivityTestRule =
-            new ChromeTabbedActivityTestRule();
-
     private static final String TAG = "TypedUrlsTest";
 
     private static final String TYPED_URLS_TYPE = "Typed URLs";
@@ -75,7 +70,6 @@
     @Before
     public void setUp() throws Exception {
         mSyncTestRule.setUpAccountAndEnableSyncForTesting();
-        mActivityTestRule.startMainActivityOnBlankPage();
         // Make sure the initial state is clean.
         assertClientTypedUrlCount(0);
         assertServerTypedUrlCountWithName(0, URL);
@@ -128,7 +122,7 @@
     private void loadUrlByTyping(final String url) {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             LoadUrlParams params = new LoadUrlParams(url, PageTransition.TYPED);
-            mActivityTestRule.getActivity().getActivityTab().loadUrl(params);
+            mSyncTestRule.getActivity().getActivityTab().loadUrl(params);
         });
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragmentTest.java
index 958c036c..a121f09e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragmentTest.java
@@ -12,7 +12,6 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -24,7 +23,6 @@
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.sync.SyncTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.components.sync.PassphraseType;
 
 /**
@@ -36,10 +34,6 @@
     @Rule
     public SyncTestRule mSyncTestRule = new SyncTestRule();
 
-    @Rule
-    public final ChromeTabbedActivityTestRule mActivityTestRule =
-            new ChromeTabbedActivityTestRule();
-
     private static final String TAG = "PassphraseTypeDialogFragmentTest";
 
     private static final boolean ENABLED = true;
@@ -60,11 +54,6 @@
 
     private PassphraseTypeDialogFragment mTypeFragment;
 
-    @Before
-    public void setUp() {
-        mActivityTestRule.startMainActivityOnBlankPage();
-    }
-
     @Test
     @SmallTest
     @Feature({"Sync"})
@@ -130,7 +119,7 @@
 
     public void createFragment(@PassphraseType int type, boolean isEncryptEverythingAllowed) {
         mTypeFragment = PassphraseTypeDialogFragment.create(type, 0, isEncryptEverythingAllowed);
-        mTypeFragment.show(mActivityTestRule.getActivity().getSupportFragmentManager(), TAG);
+        mTypeFragment.show(mSyncTestRule.getActivity().getSupportFragmentManager(), TAG);
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java
index 4595b54d..ae3ea94 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java
@@ -118,7 +118,7 @@
         private String mUrl;
 
         public TestLocationBarModel() {
-            super(ContextUtils.getApplicationContext());
+            super(ContextUtils.getApplicationContext(), NewTabPageDelegate.EMPTY);
             initializeWithNative();
 
             Tab tab = new MockTab(0, false) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java
index 6582cf5..341d3702 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java
@@ -63,7 +63,8 @@
         NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess();
 
         mocker.mock(SecurityStateModelJni.TEST_HOOKS, mSecurityStateMocks);
-        mLocationBarModel = spy(new LocationBarModel(ContextUtils.getApplicationContext()));
+        mLocationBarModel = spy(new LocationBarModel(
+                ContextUtils.getApplicationContext(), NewTabPageDelegate.EMPTY));
         mLocationBarModel.initializeWithNative();
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/native_page/NativePageFactoryTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/native_page/NativePageFactoryTest.java
index 74cc462..3c2af79 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/native_page/NativePageFactoryTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/native_page/NativePageFactoryTest.java
@@ -13,9 +13,9 @@
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.chrome.browser.native_page.NativePageFactory.NativePageType;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.ui.native_page.NativePage;
+import org.chromium.chrome.browser.ui.native_page.NativePage.NativePageType;
 import org.chromium.components.embedder_support.util.UrlConstants;
 
 /**
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandlerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandlerTest.java
index 99a8db8..88a6bb1 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandlerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandlerTest.java
@@ -23,7 +23,6 @@
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.night_mode.NightModeStateProvider;
-import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.ui.TabObscuringHandler;
 import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
 
@@ -48,7 +47,7 @@
     @Mock
     private ScrimCoordinator mScrimCoordinator;
     @Mock
-    private NewTabPage mNewTabPage;
+    private NewTabPageDelegate mNewTabPageDelegate;
 
     LocationBarFocusScrimHandler mScrimHandler;
 
@@ -63,6 +62,8 @@
 
     @Test
     public void testScrimShown_thenHidden() {
+        doReturn(mNewTabPageDelegate).when(mToolbarDataProvider).getNewTabPageDelegate();
+        doReturn(false).when(mNewTabPageDelegate).isLocationBarShown();
         mScrimHandler.onUrlFocusChange(true);
 
         verify(mScrimCoordinator).showScrim(any());
@@ -77,8 +78,8 @@
 
     @Test
     public void testScrimShown_afterAnimation() {
-        doReturn(mNewTabPage).when(mToolbarDataProvider).getNewTabPageForCurrentTab();
-        doReturn(true).when(mNewTabPage).isLocationBarShownInNTP();
+        doReturn(mNewTabPageDelegate).when(mToolbarDataProvider).getNewTabPageDelegate();
+        doReturn(true).when(mNewTabPageDelegate).isLocationBarShown();
         mScrimHandler.onUrlFocusChange(true);
 
         verify(mScrimCoordinator, never()).showScrim(any());
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java
index 277cbe16..942a28c 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java
@@ -71,14 +71,14 @@
 
     private static class TestIncognitoLocationBarModel extends LocationBarModel {
         public TestIncognitoLocationBarModel(Tab tab) {
-            super(ContextUtils.getApplicationContext());
+            super(ContextUtils.getApplicationContext(), NewTabPageDelegate.EMPTY);
             setTab(tab, /*incognito=*/true);
         }
     }
 
     private static class TestRegularLocationBarModel extends LocationBarModel {
         public TestRegularLocationBarModel(Tab tab) {
-            super(ContextUtils.getApplicationContext());
+            super(ContextUtils.getApplicationContext(), NewTabPageDelegate.EMPTY);
             setTab(tab, /*incognito=*/false);
         }
     }
diff --git a/chrome/android/modules/buildflags.gni b/chrome/android/modules/buildflags.gni
index c60310e..94c6293 100644
--- a/chrome/android/modules/buildflags.gni
+++ b/chrome/android/modules/buildflags.gni
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/android/channel.gni")
 import("//build/config/android/config.gni")
 import("//build/config/compiler/compiler.gni")
 import("//device/vr/buildflags/buildflags.gni")
@@ -10,7 +11,10 @@
   # 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.
-  enable_chrome_module = false
+  # 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"
 }
 
 # If true, lld is used to partition feature code into separate libraries, which
diff --git a/chrome/android/modules/chime/internal/java/src/org/chromium/chrome/modules/chime/ChimeModuleEntryImpl.java b/chrome/android/modules/chime/internal/java/src/org/chromium/chrome/modules/chime/ChimeModuleEntryImpl.java
index 905a730..e9bdf14 100644
--- a/chrome/android/modules/chime/internal/java/src/org/chromium/chrome/modules/chime/ChimeModuleEntryImpl.java
+++ b/chrome/android/modules/chime/internal/java/src/org/chromium/chrome/modules/chime/ChimeModuleEntryImpl.java
@@ -13,8 +13,5 @@
 @UsedByReflection("ChimeModule")
 public class ChimeModuleEntryImpl implements ChimeModuleEntry {
     @Override
-    public void initialize() {}
-
-    @Override
     public void register() {}
 }
diff --git a/chrome/android/modules/chime/public/java/src/org/chromium/chrome/modules/chime/ChimeModuleEntry.java b/chrome/android/modules/chime/public/java/src/org/chromium/chrome/modules/chime/ChimeModuleEntry.java
index b5e98fd..2fa5d52 100644
--- a/chrome/android/modules/chime/public/java/src/org/chromium/chrome/modules/chime/ChimeModuleEntry.java
+++ b/chrome/android/modules/chime/public/java/src/org/chromium/chrome/modules/chime/ChimeModuleEntry.java
@@ -12,12 +12,7 @@
 @ModuleInterface(module = "chime", impl = "org.chromium.chrome.modules.chime.ChimeModuleEntryImpl")
 public interface ChimeModuleEntry {
     /**
-     * Initializes the Chime component.
-     */
-    void initialize();
-
-    /**
-     * Registers the Chime notification and starts to get notification payloads from servers.
+     * Registers the Chime notification SDK to the server.
      */
     void register();
 }
diff --git a/chrome/android/modules/chrome_bundle_tmpl.gni b/chrome/android/modules/chrome_bundle_tmpl.gni
index 5b74b0d..5eb2be9 100644
--- a/chrome/android/modules/chrome_bundle_tmpl.gni
+++ b/chrome/android/modules/chrome_bundle_tmpl.gni
@@ -48,10 +48,25 @@
           _module_desc.supports_isolated_split) {
         _module_descs += [ _module_desc ]
       } else {
+        _shared_libraries = []
+        if (defined(_module_desc.native_deps) &&
+            _module_desc.native_deps != []) {
+          _arch = ""
+          _toolchain = ""
+          if (android_64bit_target_cpu) {
+            if (invoker.is_64_bit_browser) {
+              _arch = "_64"
+            } else {
+              _toolchain = "($android_secondary_abi_toolchain)"
+            }
+          }
+          _shared_libraries += [ "//chrome/android:libmonochrome${_arch}_${_module_desc.name}${_toolchain}" ]
+        }
         _module_desc_target_name =
             "${target_name}__${_module_desc.name}__module_desc_java"
         module_desc_java(_module_desc_target_name) {
           module_name = _module_desc.name
+          shared_libraries = _shared_libraries
           if (defined(_module_desc.pak_deps)) {
             paks = _module_desc.paks
           }
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 465b7db..6696b14 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -954,6 +954,17 @@
     Please retry. If you see this error again please contact your support representative.
   </message>
 
+  <!-- Strings for parental handoff login screen -->
+  <message name="IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_TITLE" desc="Title of screen which tells user that the parent can handoff the device to supervised user.">
+    Now it's <ph name="SUPERVISED_USER_NAME">$1<ex>Child 1</ex></ph>'s turn
+  </message>
+  <message name="IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_SUBTITLE" desc="Subtitle of screen which tells user that the parent can handoff the device to supervised user.">
+    You can hand this Chromebook to <ph name="SUPERVISED_USER_NAME">$1<ex>Child 1</ex></ph>. Setup is almost done, then it's time to explore.
+  </message>
+  <message name="IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_NEXT_BUTTON" desc="Next button of parental handoff screen">
+    Next
+  </message>
+
   <!-- Strings for family link notice screen -->
   <message name="IDS_LOGIN_FAMILY_LINK_NOTICE_SCREEN_TITLE" desc="Title of the screen which tells user they can add parental control later.">
     Add parental controls after setup
@@ -5476,6 +5487,9 @@
   <message name="IDS_PLUGIN_VM_INSUFFICIENT_DISK_SPACE_MESSAGE" desc="Error message shown if Plugin VM installation fails because there is not enough free space on the device.">
       Your device is low on storage. At least <ph name="MINIMUM_SPACE">$1<ex>16GB</ex></ph> of free space is required to use <ph name="APP_NAME">$2<ex>Plugin VM</ex></ph>. To increase free space, delete files from device.
   </message>
+  <message name="IDS_PLUGIN_VM_APP_NAME_WINDOWS_SUFFIX" desc="Application name with ' (Windows)' suffix. Do not translate 'Windows'">
+    <ph name="APP_NAME">$1<ex>Notepad</ex></ph> (Windows)
+  </message>
 
   <!-- Strings for camera/mic permission -->
   <message name="IDS_CAMERA_NOTIFICATION_SOURCE" desc="The name of the source of a camera notification ">
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_NEXT_BUTTON.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_NEXT_BUTTON.png.sha1
new file mode 100644
index 0000000..0425e08
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_NEXT_BUTTON.png.sha1
@@ -0,0 +1 @@
+5110db314fcfbbc1194cd27d5336c88de1790aa2
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_SUBTITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_SUBTITLE.png.sha1
new file mode 100644
index 0000000..79b9304b
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_SUBTITLE.png.sha1
@@ -0,0 +1 @@
+72c5848be1b964cd6e77471c295e4ad19888692e
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_TITLE.png.sha1
new file mode 100644
index 0000000..f1578c3d
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_TITLE.png.sha1
@@ -0,0 +1 @@
+f7c276d755adae2584036084356c2521de1602d9
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_PLUGIN_VM_APP_NAME_WINDOWS_SUFFIX.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_PLUGIN_VM_APP_NAME_WINDOWS_SUFFIX.png.sha1
new file mode 100644
index 0000000..03a8fff
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_PLUGIN_VM_APP_NAME_WINDOWS_SUFFIX.png.sha1
@@ -0,0 +1 @@
+86d6f07a4698f6865724566b889ffb391951e268
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index bfc9a94..cc0a0e3f 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -6470,13 +6470,8 @@
 
 #if BUILDFLAG(ENABLE_TAB_SEARCH)
     {"enable-tab-search", flag_descriptions::kEnableTabSearchName,
-     flag_descriptions::kEnableTabSearchDescription, kOsCrOS,
+     flag_descriptions::kEnableTabSearchDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kTabSearch)},
-
-    {"enable-tab-search-fixed-entrypoint",
-     flag_descriptions::kEnableTabSearchFixedEntrypointName,
-     flag_descriptions::kEnableTabSearchFixedEntrypointDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(features::kTabSearchFixedEntrypoint)},
 #endif  // BUILDFLAG(ENABLE_TAB_SEARCH)
 
 #if defined(OS_ANDROID)
diff --git a/chrome/browser/android/vr/register_jni_monochrome.cc b/chrome/browser/android/vr/register_jni_monochrome.cc
index 24834a9..66f7c93 100644
--- a/chrome/browser/android/vr/register_jni_monochrome.cc
+++ b/chrome/browser/android/vr/register_jni_monochrome.cc
@@ -4,9 +4,24 @@
 
 #include "chrome/browser/android/vr/register_jni.h"
 
+#include "chrome/browser/android/vr/register_gvr_jni.h"
+
 namespace vr {
 
 bool RegisterJni(JNIEnv* env) {
+  // The GVR Java code is normally in the vr DFM, which will be loaded into the
+  // base class loader. If the enable_chrome_module gn arg is enabled, the GVR
+  // Java code will be in the chrome DFM, which is loaded as an isolated split.
+  // This means the Java code is no longer automatically loaded in the base
+  // class loader. Automatic JNI registration only works for native methods
+  // associated with the base class loader (which loaded libmonochrome.so, so
+  // will look for symbols there). Most of Chrome's native methods are in
+  // GEN_JNI.java which is present in the base module, so do not need manual
+  // registration. Since GVR has native methods outside of GEN_JNI.java which
+  // are not present in the base module, these must be manually registered.
+  if (!vr::RegisterGvrJni(env)) {
+    return false;
+  }
   return true;
 }
 
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 5f66e7b..52ef761 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -500,6 +500,9 @@
         <include name="IDR_ARC_OVERVIEW_TRACING_UI_JS" file="resources\chromeos\arc_graphics_tracing\arc_overview_tracing_ui.js" type="BINDATA" />
         <include name="IDR_ARC_TRACING_UI_JS" file="resources\chromeos\arc_graphics_tracing\arc_tracing_ui.js" type="BINDATA" />
         <include name="IDR_ARC_TRACING_CSS" file="resources\chromeos\arc_graphics_tracing\arc_tracing.css" type="BINDATA" />
+        <include name="IDR_ARC_POWER_CONTROL_HTML" file="resources\chromeos\arc_power_control\arc_power_control.html" type="BINDATA"/>
+        <include name="IDR_ARC_POWER_CONTROL_JS" file="resources\chromeos\arc_power_control\arc_power_control.js" type="BINDATA" />
+        <include name="IDR_ARC_POWER_CONTROL_CSS" file="resources\chromeos\arc_power_control\arc_power_control.css" type="BINDATA" />
       </if>
       <if expr="chromeos">
         <include name="IDR_MACHINE_LEARNING_INTERNALS_GRAPH_EXECUTOR_MOJO_JS" file="${root_gen_dir}\chromeos\services\machine_learning\public\mojom\graph_executor.mojom-lite.js" use_base_dir="false" type="BINDATA" />
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 315e8c9..b8dd278 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1745,6 +1745,8 @@
     "login/screens/network_screen.h",
     "login/screens/packaged_license_screen.cc",
     "login/screens/packaged_license_screen.h",
+    "login/screens/parental_handoff_screen.cc",
+    "login/screens/parental_handoff_screen.h",
     "login/screens/recommend_apps/fake_recommend_apps_fetcher.cc",
     "login/screens/recommend_apps/fake_recommend_apps_fetcher.h",
     "login/screens/recommend_apps/recommend_apps_fetcher.cc",
diff --git a/chrome/browser/chromeos/app_mode/app_session_unittest.cc b/chrome/browser/chromeos/app_mode/app_session_unittest.cc
index 45ee13f..1e562a1 100644
--- a/chrome/browser/chromeos/app_mode/app_session_unittest.cc
+++ b/chrome/browser/chromeos/app_mode/app_session_unittest.cc
@@ -44,15 +44,15 @@
   TestingProfile profile;
 
   Browser::CreateParams params(&profile, true);
-  auto app_browser = CreateBrowserWithTestWindowForParams(&params);
+  auto app_browser = CreateBrowserWithTestWindowForParams(params);
 
   app_session->InitForWebKiosk(app_browser.get());
 
   Browser::CreateParams another_params(&profile, true);
-  auto another_browser = CreateBrowserWithTestWindowForParams(&another_params);
+  auto another_browser = CreateBrowserWithTestWindowForParams(another_params);
 
   base::RunLoop loop;
-  static_cast<TestBrowserWindow*>(another_params.window)
+  static_cast<TestBrowserWindow*>(another_browser->window())
       ->SetCloseCallback(
           base::BindLambdaForTesting([&loop]() { loop.Quit(); }));
   loop.Run();
diff --git a/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.cc b/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.cc
index 08309b43..a15ddb3a 100644
--- a/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.cc
+++ b/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.cc
@@ -8,10 +8,10 @@
 #include "base/metrics/histogram_functions.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
+#include "chrome/browser/memory/memory_kills_monitor.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
-#include "components/arc/metrics/arc_metrics_service.h"
 
 namespace arc {
 namespace {
@@ -54,11 +54,13 @@
       arc_metrics_service_(ArcMetricsService::GetForBrowserContext(context)) {
   arc_app_list_prefs_->AddObserver(this);
   arc::ArcSessionManager::Get()->AddObserver(this);
+  arc_metrics_service_->AddAppKillObserver(this);
 }
 
 void ArcMetricsServiceProxy::Shutdown() {
   arc::ArcSessionManager::Get()->RemoveObserver(this);
   arc_app_list_prefs_->RemoveObserver(this);
+  arc_metrics_service_->RemoveAppKillObserver(this);
 }
 
 void ArcMetricsServiceProxy::OnTaskCreated(int32_t task_id,
@@ -81,4 +83,13 @@
   }
 }
 
+void ArcMetricsServiceProxy::OnArcLowMemoryKill() {
+  memory::MemoryKillsMonitor::LogLowMemoryKill("APP", 0);
+}
+
+void ArcMetricsServiceProxy::OnArcOOMKillCount(
+    unsigned long current_oom_kills) {
+  memory::MemoryKillsMonitor::LogArcOOMKill(current_oom_kills);
+}
+
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.h b/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.h
index 603eed1..721c0d65 100644
--- a/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.h
+++ b/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager_observer.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "components/arc/metrics/arc_metrics_service.h"
 #include "components/keyed_service/core/keyed_service.h"
 
 namespace content {
@@ -17,14 +18,14 @@
 namespace arc {
 
 class ArcBridgeService;
-class ArcMetricsService;
 
 // Proxy to ArcMetricsService for functionalities that depend on code under
 // chrome/browser. Should be merged into ArcMetricsService once dependency
 // issues are cleared. TODO(crbug.com/903048): Remove the proxy.
 class ArcMetricsServiceProxy : public KeyedService,
                                public ArcAppListPrefs::Observer,
-                               public ArcSessionManagerObserver {
+                               public ArcSessionManagerObserver,
+                               public ArcMetricsService::AppKillObserver {
  public:
   static ArcMetricsServiceProxy* GetForBrowserContext(
       content::BrowserContext* context);
@@ -46,6 +47,10 @@
   // ArcSessionManagerObserver overrides.
   void OnArcSessionStopped(ArcStopReason stop_reason) override;
 
+  // ArcMetricsService::AppKillObserver overrides.
+  void OnArcLowMemoryKill() override;
+  void OnArcOOMKillCount(unsigned long current_oom_kills) override;
+
  private:
   ArcAppListPrefs* const arc_app_list_prefs_;
   ArcMetricsService* const arc_metrics_service_;
diff --git a/chrome/browser/chromeos/arc/tracing/arc_value_event.h b/chrome/browser/chromeos/arc/tracing/arc_value_event.h
index 9120f44c..6ab1740a 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_value_event.h
+++ b/chrome/browser/chromeos/arc/tracing/arc_value_event.h
@@ -29,6 +29,8 @@
     kGpuPower,
     kMemoryPower,
     kPackagePowerConstraint,
+    kWakenessfullMode,
+    kThrottlingMode,
   };
 
   ArcValueEvent(int64_t timestamp, Type type, int value);
diff --git a/chrome/browser/chromeos/file_manager/guest_os_file_tasks.cc b/chrome/browser/chromeos/file_manager/guest_os_file_tasks.cc
index a61ea03..ea09bd0 100644
--- a/chrome/browser/chromeos/file_manager/guest_os_file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/guest_os_file_tasks.cc
@@ -51,7 +51,6 @@
 // upon whether it "thinks" it is binary or text content.
 constexpr char kUnknownBinaryMimeType[] = "application/octet-stream";
 constexpr char kUnknownTextMimeType[] = "text/plain";
-constexpr char kPluginVmAppNameSuffix[] = " (Windows)";
 
 bool HasSupportedMimeType(
     const std::set<std::string>& supported_mime_types,
@@ -182,7 +181,6 @@
                                              registration)) {
           continue;
         }
-        app_names->push_back(registration.Name());
         break;
 
       case guest_os::GuestOsRegistryService::VmType::
@@ -190,7 +188,6 @@
         if (!AppSupportsExtensionOfAllEntries(entries, registration)) {
           continue;
         }
-        app_names->push_back(registration.Name() + kPluginVmAppNameSuffix);
         break;
 
       default:
@@ -199,6 +196,7 @@
     }
 
     app_ids->push_back(app_id);
+    app_names->push_back(registration.Name());
     vm_types->push_back(registration.VmType());
   }
 }
diff --git a/chrome/browser/chromeos/guest_os/guest_os_registry_service.cc b/chrome/browser/chromeos/guest_os/guest_os_registry_service.cc
index 1a8c813..f572d7d 100644
--- a/chrome/browser/chromeos/guest_os/guest_os_registry_service.cc
+++ b/chrome/browser/chromeos/guest_os/guest_os_registry_service.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/task/thread_pool.h"
 #include "base/time/clock.h"
@@ -383,6 +384,12 @@
 }
 
 std::string GuestOsRegistryService::Registration::Name() const {
+  if (VmType() ==
+      GuestOsRegistryService::VmType::ApplicationList_VmType_PLUGIN_VM) {
+    return l10n_util::GetStringFUTF8(
+        IDS_PLUGIN_VM_APP_NAME_WINDOWS_SUFFIX,
+        base::UTF8ToUTF16(LocalizedString(guest_os::prefs::kAppNameKey)));
+  }
   return LocalizedString(guest_os::prefs::kAppNameKey);
 }
 
diff --git a/chrome/browser/chromeos/guest_os/guest_os_registry_service_unittest.cc b/chrome/browser/chromeos/guest_os/guest_os_registry_service_unittest.cc
index 67de2a0..6db4ec287 100644
--- a/chrome/browser/chromeos/guest_os/guest_os_registry_service_unittest.cc
+++ b/chrome/browser/chromeos/guest_os/guest_os_registry_service_unittest.cc
@@ -625,4 +625,30 @@
   EXPECT_THAT(GetEnabledAppIds(), testing::IsEmpty());
 }
 
+TEST_F(GuestOsRegistryServiceTest, PluginVmNameSuffix) {
+  ApplicationList crostini_list;
+  crostini_list.set_vm_type(
+      GuestOsRegistryService::VmType::ApplicationList_VmType_TERMINA);
+  crostini_list.set_vm_name("termina");
+  crostini_list.set_container_name("penguin");
+  *crostini_list.add_apps() = crostini::CrostiniTestHelper::BasicApp("c");
+  std::string c =
+      crostini::CrostiniTestHelper::GenerateAppId("c", "termina", "penguin");
+  service()->UpdateApplicationList(crostini_list);
+
+  ApplicationList plugin_vm_list;
+  plugin_vm_list.set_vm_type(
+      GuestOsRegistryService::VmType::ApplicationList_VmType_PLUGIN_VM);
+  plugin_vm_list.set_vm_name("PvmDefault");
+  plugin_vm_list.set_container_name("penguin");
+  *plugin_vm_list.add_apps() = crostini::CrostiniTestHelper::BasicApp("p");
+  std::string p =
+      crostini::CrostiniTestHelper::GenerateAppId("p", "PvmDefault", "penguin");
+  service()->UpdateApplicationList(plugin_vm_list);
+
+  // Crostini apps have name unchanged, PluginVM has ' (Windows)' suffix.
+  EXPECT_EQ("c", service()->GetRegistration(c)->Name());
+  EXPECT_EQ("p (Windows)", service()->GetRegistration(p)->Name());
+}
+
 }  // namespace guest_os
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 342efe6..a4ff04fa 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine.cc
@@ -200,14 +200,21 @@
       return;
     }
   }
+
+  auto key_event = ime::mojom::PhysicalKeyEvent::New(
+      event.type == "keydown" ? ime::mojom::KeyEventType::kKeyDown
+                              : ime::mojom::KeyEventType::kKeyUp,
+      event.code, event.key, ModifierStateFromEvent(event));
+
   if (ShouldUseRuleBasedMojoEngine(engine_id) && remote_to_engine_.is_bound()) {
     remote_to_engine_->ProcessKeypressForRulebased(
-        ime::mojom::PhysicalKeyEvent::New(
-            event.type == "keydown" ? ime::mojom::KeyEventType::kKeyDown
-                                    : ime::mojom::KeyEventType::kKeyUp,
-            event.code, event.key, ModifierStateFromEvent(event)),
-        base::BindOnce(&ImeObserver::OnKeyEventResponse, base::Unretained(this),
-                       base::Time::Now(), std::move(callback)));
+        std::move(key_event),
+        base::BindOnce(&ImeObserver::OnRuleBasedKeyEventResponse,
+                       base::Unretained(this), base::Time::Now(),
+                       std::move(callback)));
+  } else if (ShouldUseFstMojoEngine(engine_id) &&
+             remote_to_engine_.is_bound()) {
+    remote_to_engine_->OnKeyEvent(std::move(key_event), std::move(callback));
   } else {
     base_observer_->OnKeyEvent(engine_id, event, std::move(callback));
   }
@@ -353,7 +360,7 @@
   active_engine_id_.reset();
 }
 
-void NativeInputMethodEngine::ImeObserver::OnKeyEventResponse(
+void NativeInputMethodEngine::ImeObserver::OnRuleBasedKeyEventResponse(
     base::Time start,
     ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback,
     ime::mojom::KeypressResponseForRulebasedPtr response) {
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine.h b/chrome/browser/chromeos/input_method/native_input_method_engine.h
index be60233..fea9d06 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine.h
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine.h
@@ -96,6 +96,8 @@
     void ProcessKeypressForRulebased(
         ime::mojom::PhysicalKeyEventPtr event,
         ProcessKeypressForRulebasedCallback callback) override {}
+    void OnKeyEvent(ime::mojom::PhysicalKeyEventPtr event,
+                    OnKeyEventCallback callback) override {}
     void ResetForRulebased() override {}
     void GetRulebasedKeypressCountForTesting(
         GetRulebasedKeypressCountForTestingCallback callback) override {}
@@ -114,8 +116,8 @@
     // Called when there's a connection error.
     void OnError(base::Time start);
 
-    // Called when a key press is processed by Mojo.
-    void OnKeyEventResponse(
+    // Called when a rule-based key press is processed by Mojo.
+    void OnRuleBasedKeyEventResponse(
         base::Time start,
         ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback,
         ime::mojom::KeypressResponseForRulebasedPtr response);
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc b/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc
index 9f287e1e..fa99024 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc
@@ -150,7 +150,7 @@
 
  protected:
   void SetUp() override {
-    chromeos::ime::FakeEngineMainEntryForTesting();
+    chromeos::ime::FakeEngineMainEntryForTesting(nullptr);
     mojo::core::Init();
     InProcessBrowserTest::SetUp();
     ui::IMEBridge::Initialize();
diff --git a/chrome/browser/chromeos/login/debug_overlay_browsertest.cc b/chrome/browser/chromeos/login/debug_overlay_browsertest.cc
index daf9d2a..94961621 100644
--- a/chrome/browser/chromeos/login/debug_overlay_browsertest.cc
+++ b/chrome/browser/chromeos/login/debug_overlay_browsertest.cc
@@ -22,8 +22,8 @@
 constexpr char kDebugOverlay[] = "debuggerOverlay";
 constexpr char kScreensPanel[] = "DebuggerPanelScreens";
 
-constexpr int kOobeScreensCount = 37;
-constexpr int kLoginScreensCount = 32;
+constexpr int kOobeScreensCount = 38;
+constexpr int kLoginScreensCount = 33;
 
 std::string ElementsInPanel(const std::string& panel) {
   return base::StrCat({"$('", panel, "').children.length"});
diff --git a/chrome/browser/chromeos/login/screens/parental_handoff_screen.cc b/chrome/browser/chromeos/login/screens/parental_handoff_screen.cc
new file mode 100644
index 0000000..caca1165
--- /dev/null
+++ b/chrome/browser/chromeos/login/screens/parental_handoff_screen.cc
@@ -0,0 +1,109 @@
+// 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 "chrome/browser/chromeos/login/screens/parental_handoff_screen.h"
+
+#include <string>
+
+#include "base/strings/string16.h"
+#include "chrome/browser/chromeos/login/oobe_screen.h"
+#include "chrome/browser/chromeos/login/screen_manager.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/supervised_user/supervised_user_features.h"
+#include "chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.h"
+#include "chrome/grit/chromium_strings.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/user_manager/user.h"
+#include "components/user_manager/user_manager.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace chromeos {
+
+namespace {
+
+constexpr char kUserActionNext[] = "next";
+
+base::string16 GetActiveUserName() {
+  const user_manager::User* user =
+      user_manager::UserManager::Get()->GetActiveUser();
+  if (!user || !user->IsChild())
+    return base::string16();
+  return user->GetDisplayName();
+}
+
+}  // namespace
+
+// static
+ParentalHandoffScreen* ParentalHandoffScreen::Get(
+    ScreenManager* screen_manager) {
+  return static_cast<ParentalHandoffScreen*>(
+      screen_manager->GetScreen(ParentalHandoffScreenView::kScreenId));
+}
+
+// static
+std::string ParentalHandoffScreen::GetResultString(
+    ParentalHandoffScreen::Result result) {
+  switch (result) {
+    case ParentalHandoffScreen::Result::DONE:
+      return "Done";
+    case ParentalHandoffScreen::Result::SKIPPED:
+      return BaseScreen::kNotApplicable;
+  }
+}
+
+ParentalHandoffScreen::ParentalHandoffScreen(
+    ParentalHandoffScreenView* view,
+    const ScreenExitCallback& exit_callback)
+    : BaseScreen(ParentalHandoffScreenView::kScreenId,
+                 OobeScreenPriority::DEFAULT),
+      view_(view),
+      exit_callback_(exit_callback) {
+  if (view_)
+    view_->Bind(this);
+}
+
+ParentalHandoffScreen::~ParentalHandoffScreen() {
+  if (view_)
+    view_->Unbind();
+}
+
+void ParentalHandoffScreen::OnViewDestroyed(ParentalHandoffScreenView* view) {
+  if (view_ == view)
+    view_ = nullptr;
+}
+
+bool ParentalHandoffScreen::MaybeSkip(WizardContext* context) {
+  Profile* profile = ProfileManager::GetActiveUserProfile();
+  if (profile->IsChild() && supervised_users::IsEduCoexistenceFlowV2Enabled()) {
+    return false;
+  }
+
+  exit_callback_.Run(Result::SKIPPED);
+  return true;
+}
+
+void ParentalHandoffScreen::ShowImpl() {
+  if (!view_)
+    return;
+
+  base::string16 user_name = GetActiveUserName();
+
+  view_->Show(l10n_util::GetStringFUTF16(
+                  IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_TITLE, user_name),
+              l10n_util::GetStringFUTF16(
+                  IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_SUBTITLE, user_name));
+}
+void ParentalHandoffScreen::HideImpl() {}
+
+void ParentalHandoffScreen::OnUserAction(const std::string& action_id) {
+  if (action_id == kUserActionNext) {
+    exit_callback_.Run(Result::DONE);
+  } else {
+    BaseScreen::OnUserAction(action_id);
+  }
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/parental_handoff_screen.h b/chrome/browser/chromeos/login/screens/parental_handoff_screen.h
new file mode 100644
index 0000000..79b4dbd2
--- /dev/null
+++ b/chrome/browser/chromeos/login/screens/parental_handoff_screen.h
@@ -0,0 +1,54 @@
+// 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 CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_PARENTAL_HANDOFF_SCREEN_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_PARENTAL_HANDOFF_SCREEN_H_
+
+#include <string>
+
+#include "base/bind.h"
+#include "chrome/browser/chromeos/login/screens/base_screen.h"
+
+namespace chromeos {
+
+class ParentalHandoffScreenView;
+class WizardContext;
+class ScreenManager;
+
+class ParentalHandoffScreen : public BaseScreen {
+ public:
+  enum class Result { DONE, SKIPPED };
+
+  static ParentalHandoffScreen* Get(ScreenManager* screen_manager);
+  static std::string GetResultString(Result result);
+
+  using ScreenExitCallback = base::RepeatingCallback<void(Result)>;
+  ParentalHandoffScreen(ParentalHandoffScreenView* view,
+                        const ScreenExitCallback& exit_callback);
+  ParentalHandoffScreen(const ParentalHandoffScreen&) = delete;
+  ParentalHandoffScreen& operator=(const ParentalHandoffScreen&) = delete;
+  ~ParentalHandoffScreen() override;
+
+  void OnViewDestroyed(ParentalHandoffScreenView* view);
+
+  ScreenExitCallback get_exit_callback_for_test() { return exit_callback_; }
+
+  void set_exit_callback_for_test(const ScreenExitCallback& exit_callback) {
+    exit_callback_ = exit_callback;
+  }
+
+ private:
+  // BaseScreen:
+  bool MaybeSkip(WizardContext* context) override;
+  void ShowImpl() override;
+  void HideImpl() override;
+  void OnUserAction(const std::string& action_id) override;
+
+  ParentalHandoffScreenView* view_ = nullptr;
+  ScreenExitCallback exit_callback_;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_PARENTAL_HANDOFF_SCREEN_H_
diff --git a/chrome/browser/chromeos/login/screens/parental_handoff_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/parental_handoff_screen_browsertest.cc
new file mode 100644
index 0000000..5d74300
--- /dev/null
+++ b/chrome/browser/chromeos/login/screens/parental_handoff_screen_browsertest.cc
@@ -0,0 +1,197 @@
+// 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 "chrome/browser/chromeos/login/screens/parental_handoff_screen.h"
+
+#include "base/callback.h"
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/chromeos/login/screens/edu_coexistence_login_screen.h"
+#include "chrome/browser/chromeos/login/test/fake_gaia_mixin.h"
+#include "chrome/browser/chromeos/login/test/js_checker.h"
+#include "chrome/browser/chromeos/login/test/local_policy_test_server_mixin.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
+#include "chrome/browser/chromeos/login/test/oobe_base_test.h"
+#include "chrome/browser/chromeos/login/test/oobe_screen_exit_waiter.h"
+#include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
+#include "chrome/browser/chromeos/login/test/user_policy_mixin.h"
+#include "chrome/browser/chromeos/login/test/wizard_controller_screen_exit_waiter.h"
+#include "chrome/browser/chromeos/login/wizard_context.h"
+#include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "chrome/browser/supervised_user/supervised_user_features.h"
+#include "chrome/browser/supervised_user/supervised_user_service.h"
+#include "chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h"
+#include "components/account_id/account_id.h"
+#include "content/public/test/browser_test.h"
+
+namespace chromeos {
+
+namespace {
+
+const test::UIPath kParentalHandoffDialog = {"parental-handoff",
+                                             "parentalHandoffDialog"};
+const test::UIPath kNextButton = {"parental-handoff", "nextButton"};
+
+SystemWebDialogDelegate* GetEduCoexistenceLoginDialog() {
+  return chromeos::SystemWebDialogDelegate::FindInstance(
+      SupervisedUserService::GetEduCoexistenceLoginUrl());
+}
+
+}  // namespace
+
+class ParentalHandoffScreenBrowserTest : public OobeBaseTest {
+ public:
+  ParentalHandoffScreenBrowserTest();
+  ParentalHandoffScreenBrowserTest(const ParentalHandoffScreenBrowserTest&) =
+      delete;
+  ParentalHandoffScreenBrowserTest& operator=(
+      const ParentalHandoffScreenBrowserTest&) = delete;
+  ~ParentalHandoffScreenBrowserTest() override = default;
+
+  void SetUpOnMainThread() override;
+
+ protected:
+  void WaitForScreenExit();
+
+  ParentalHandoffScreen* GetParentalHandoffScreen();
+
+  const base::Optional<ParentalHandoffScreen::Result>& result() const {
+    return result_;
+  }
+
+  LoginManagerMixin& login_manager_mixin() { return login_manager_mixin_; }
+
+  base::HistogramTester& histogram_tester() { return histogram_tester_; }
+
+ private:
+  void HandleScreenExit(ParentalHandoffScreen::Result result);
+
+  base::OnceCallback<void()> quit_closure_;
+
+  base::Optional<ParentalHandoffScreen::Result> result_;
+
+  ParentalHandoffScreen::ScreenExitCallback original_callback_;
+
+  FakeGaiaMixin fake_gaia_{&mixin_host_, embedded_test_server()};
+
+  base::test::ScopedFeatureList feature_list_;
+
+  base::HistogramTester histogram_tester_;
+
+  LoginManagerMixin login_manager_mixin_{&mixin_host_, /* initial_users */ {},
+                                         &fake_gaia_};
+};
+
+ParentalHandoffScreenBrowserTest::ParentalHandoffScreenBrowserTest() {
+  feature_list_.InitAndEnableFeature(supervised_users::kEduCoexistenceFlowV2);
+}
+
+void ParentalHandoffScreenBrowserTest::SetUpOnMainThread() {
+  ParentalHandoffScreen* screen = GetParentalHandoffScreen();
+  original_callback_ = screen->get_exit_callback_for_test();
+  screen->set_exit_callback_for_test(
+      base::BindRepeating(&ParentalHandoffScreenBrowserTest::HandleScreenExit,
+                          base::Unretained(this)));
+  OobeBaseTest::SetUpOnMainThread();
+}
+
+void ParentalHandoffScreenBrowserTest::WaitForScreenExit() {
+  if (result_.has_value())
+    return;
+  base::RunLoop run_loop;
+  quit_closure_ = base::BindOnce(run_loop.QuitClosure());
+  run_loop.Run();
+}
+
+ParentalHandoffScreen*
+ParentalHandoffScreenBrowserTest::GetParentalHandoffScreen() {
+  return ParentalHandoffScreen::Get(
+      WizardController::default_controller()->screen_manager());
+}
+
+void ParentalHandoffScreenBrowserTest::HandleScreenExit(
+    ParentalHandoffScreen::Result result) {
+  result_ = result;
+  original_callback_.Run(result);
+  if (quit_closure_)
+    std::move(quit_closure_).Run();
+}
+
+IN_PROC_BROWSER_TEST_F(ParentalHandoffScreenBrowserTest, RegularUserLogin) {
+  login_manager_mixin().LoginAsNewRegularUser();
+  WaitForScreenExit();
+
+  // Regular user login shouldn't show the EduCoexistenceLoginScreen.
+  EXPECT_EQ(result().value(), ParentalHandoffScreen::Result::SKIPPED);
+
+  histogram_tester().ExpectTotalCount(
+      "OOBE.StepCompletionTimeByExitReason.Parental-handoff.Done", 0);
+}
+
+class ParentalHandoffScreenChildBrowserTest
+    : public ParentalHandoffScreenBrowserTest {
+ public:
+  // Child users require a user policy, set up an empty one so the user can
+  // get through login.
+  void SetUpInProcessBrowserTestFixture() override {
+    ASSERT_TRUE(user_policy_mixin_.RequestPolicyUpdate());
+    ParentalHandoffScreenBrowserTest::SetUpInProcessBrowserTestFixture();
+  }
+
+  void LoginAsNewChildUser() {
+    WizardController::default_controller()
+        ->get_wizard_context_for_testing()
+        ->sign_in_as_child = true;
+    login_manager_mixin().LoginAsNewChildUser();
+
+    WizardControllerExitWaiter(UserCreationView::kScreenId).Wait();
+    base::RunLoop().RunUntilIdle();
+
+    ASSERT_EQ(
+        WizardController::default_controller()->current_screen()->screen_id(),
+        EduCoexistenceLoginScreen::kScreenId);
+
+    // Current screen is EduCoexistenceLoginScreen. Close it.
+    GetEduCoexistenceLoginDialog()->Close();
+
+    OobeScreenWaiter waiter(ParentalHandoffScreenView::kScreenId);
+    waiter.Wait();
+  }
+
+ protected:
+  void ClickNextButtonOnParentalHandoffScreen() {
+    test::OobeJS().ExpectVisiblePath(kParentalHandoffDialog);
+    test::OobeJS().ExpectVisiblePath(kNextButton);
+    test::OobeJS().TapOnPath(kNextButton);
+  }
+
+ private:
+  LocalPolicyTestServerMixin policy_server_mixin_{&mixin_host_};
+  UserPolicyMixin user_policy_mixin_{
+      &mixin_host_,
+      AccountId::FromUserEmailGaiaId(test::kTestEmail, test::kTestGaiaId),
+      &policy_server_mixin_};
+};
+
+IN_PROC_BROWSER_TEST_F(ParentalHandoffScreenChildBrowserTest, ChildUserLogin) {
+  LoginAsNewChildUser();
+
+  WizardController* wizard = WizardController::default_controller();
+
+  EXPECT_EQ(wizard->current_screen()->screen_id(),
+            ParentalHandoffScreenView::kScreenId);
+
+  ClickNextButtonOnParentalHandoffScreen();
+
+  WaitForScreenExit();
+
+  histogram_tester().ExpectTotalCount(
+      "OOBE.StepCompletionTimeByExitReason.Parental-handoff.Done", 1);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 029d741..027c416 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -137,6 +137,7 @@
 #include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/browser/ui/webui/chromeos/login/packaged_license_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_fatal_error_screen_handler.h"
@@ -682,6 +683,11 @@
       base::BindRepeating(&WizardController::OnSignInFatalErrorScreenExit,
                           weak_factory_.GetWeakPtr())));
 
+  append(std::make_unique<ParentalHandoffScreen>(
+      oobe_ui->GetView<ParentalHandoffScreenHandler>(),
+      base::BindRepeating(&WizardController::OnParentalHandoffScreenExit,
+                          weak_factory_.GetWeakPtr())));
+
   return result;
 }
 
@@ -875,6 +881,10 @@
   SetCurrentScreen(GetScreen(EduCoexistenceLoginScreen::kScreenId));
 }
 
+void WizardController::ShowParentalHandoffScreen() {
+  SetCurrentScreen(GetScreen(ParentalHandoffScreenView::kScreenId));
+}
+
 void WizardController::ShowActiveDirectoryPasswordChangeScreen(
     const std::string& username) {
   ActiveDirectoryPasswordChangeScreen::Get(screen_manager())
@@ -945,6 +955,13 @@
   ShowSyncConsentScreen();
 }
 
+void WizardController::OnParentalHandoffScreenExit(
+    ParentalHandoffScreen::Result result) {
+  OnScreenExit(ParentalHandoffScreenView::kScreenId,
+               ParentalHandoffScreen::GetResultString(result));
+  ShowMultiDeviceSetupScreen();
+}
+
 void WizardController::SkipToLoginForTesting() {
   VLOG(1) << "WizardController::SkipToLoginForTesting()";
   if (current_screen_ && current_screen_->screen_id() == GaiaView::kScreenId)
@@ -1399,7 +1416,7 @@
     AssistantOptInFlowScreen::Result result) {
   OnScreenExit(AssistantOptInFlowScreenView::kScreenId,
                AssistantOptInFlowScreen::GetResultString(result));
-  ShowMultiDeviceSetupScreen();
+  ShowParentalHandoffScreen();
 }
 
 void WizardController::OnMultiDeviceSetupScreenExit(
@@ -1915,7 +1932,8 @@
       current_screen_id == FingerprintSetupScreenView::kScreenId ||
       current_screen_id == ArcTermsOfServiceScreenView::kScreenId ||
       current_screen_id == DiscoverScreenView::kScreenId ||
-      current_screen_id == MarketingOptInScreenView::kScreenId) {
+      current_screen_id == MarketingOptInScreenView::kScreenId ||
+      current_screen_id == ParentalHandoffScreenView::kScreenId) {
     default_controller()->OnOobeFlowFinished();
   } else {
     LOG(WARNING) << "SkipPostLoginScreensForTesting(): Ignore screen "
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index 22e926f2..9c68709 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -42,6 +42,7 @@
 #include "chrome/browser/chromeos/login/screens/multidevice_setup_screen.h"
 #include "chrome/browser/chromeos/login/screens/network_screen.h"
 #include "chrome/browser/chromeos/login/screens/packaged_license_screen.h"
+#include "chrome/browser/chromeos/login/screens/parental_handoff_screen.h"
 #include "chrome/browser/chromeos/login/screens/recommend_apps_screen.h"
 #include "chrome/browser/chromeos/login/screens/signin_fatal_error_screen.h"
 #include "chrome/browser/chromeos/login/screens/sync_consent_screen.h"
@@ -255,6 +256,7 @@
   void ShowMarketingOptInScreen();
   void ShowPackagedLicenseScreen();
   void ShowEduCoexistenceLoginScreen();
+  void ShowParentalHandoffScreen();
 
   // Shows images login screen.
   void ShowLoginScreen();
@@ -316,6 +318,7 @@
   void OnSignInFatalErrorScreenExit();
   void OnEduCoexistenceLoginScreenExit(
       EduCoexistenceLoginScreen::Result result);
+  void OnParentalHandoffScreenExit(ParentalHandoffScreen::Result result);
 
   // Callback invoked once it has been determined whether the device is disabled
   // or not.
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper_unittest.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper_unittest.cc
index baf9e0a..20043ae 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper_unittest.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper_unittest.cc
@@ -34,16 +34,14 @@
         &mock_dlp_content_manager_);
 
     // Initialize browser.
-    params_ = std::make_unique<Browser::CreateParams>(profile(),
-                                                      /*user_gesture=*/true);
-    browser_ = CreateBrowserWithTestWindowForParams(params_.get());
+    const Browser::CreateParams params(profile(), /*user_gesture=*/true);
+    browser_ = CreateBrowserWithTestWindowForParams(params);
     tab_strip_model_ = browser_->tab_strip_model();
   }
 
   void TearDown() override {
     tab_strip_model_->CloseAllTabs();
     browser_.reset();
-    params_.reset();
 
     DlpContentManager::ResetDlpContentManagerForTesting();
 
@@ -53,7 +51,6 @@
   MockDlpContentManager mock_dlp_content_manager_;
   TabActivitySimulator tab_activity_simulator_;
   TabStripModel* tab_strip_model_;
-  std::unique_ptr<Browser::CreateParams> params_;
   std::unique_ptr<Browser> browser_;
 };
 
diff --git a/chrome/browser/devtools/devtools_file_system_indexer.cc b/chrome/browser/devtools/devtools_file_system_indexer.cc
index 542b35f..7c2ad28a 100644
--- a/chrome/browser/devtools/devtools_file_system_indexer.cc
+++ b/chrome/browser/devtools/devtools_file_system_indexer.cc
@@ -266,14 +266,14 @@
 DevToolsFileSystemIndexer::FileSystemIndexingJob::FileSystemIndexingJob(
     const FilePath& file_system_path,
     const std::vector<base::FilePath>& excluded_folders,
-    const TotalWorkCallback& total_work_callback,
+    TotalWorkCallback total_work_callback,
     const WorkedCallback& worked_callback,
-    const DoneCallback& done_callback)
+    DoneCallback done_callback)
     : file_system_path_(file_system_path),
       excluded_folders_(excluded_folders),
-      total_work_callback_(total_work_callback),
+      total_work_callback_(std::move(total_work_callback)),
       worked_callback_(worked_callback),
-      done_callback_(done_callback),
+      done_callback_(std::move(done_callback)),
       files_indexed_(0),
       stopped_(false) {
   current_trigrams_set_.resize(kTrigramCount);
@@ -322,7 +322,7 @@
 
   if (file_path.empty()) {
     content::GetUIThreadTaskRunner({})->PostTask(
-        FROM_HERE, BindOnce(total_work_callback_, file_path_times_.size()));
+        FROM_HERE, BindOnce(std::move(total_work_callback_), file_path_times_.size()));
     indexing_it_ = file_path_times_.begin();
     IndexFiles();
     return;
@@ -358,7 +358,7 @@
     return;
   if (indexing_it_ == file_path_times_.end()) {
     g_trigram_index.Get().NormalizeVectors();
-    content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, done_callback_);
+    content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(done_callback_));
     return;
   }
   FilePath file_path = indexing_it_->first;
@@ -475,17 +475,17 @@
 DevToolsFileSystemIndexer::IndexPath(
     const string& file_system_path,
     const vector<string>& excluded_folders,
-    const TotalWorkCallback& total_work_callback,
+    TotalWorkCallback total_work_callback,
     const WorkedCallback& worked_callback,
-    const DoneCallback& done_callback) {
+    DoneCallback done_callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   vector<base::FilePath> paths;
   for (const string& path : excluded_folders) {
     paths.push_back(FilePath::FromUTF8Unsafe(path));
   }
   scoped_refptr<FileSystemIndexingJob> indexing_job = new FileSystemIndexingJob(
-      FilePath::FromUTF8Unsafe(file_system_path), paths, total_work_callback,
-      worked_callback, done_callback);
+      FilePath::FromUTF8Unsafe(file_system_path), paths, std::move(total_work_callback),
+      worked_callback, std::move(done_callback));
   indexing_job->Start();
   return indexing_job;
 }
@@ -493,18 +493,18 @@
 void DevToolsFileSystemIndexer::SearchInPath(
     const std::string& file_system_path,
     const std::string& query,
-    const SearchCallback& callback) {
+    SearchCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   impl_task_runner()->PostTask(
       FROM_HERE,
       BindOnce(&DevToolsFileSystemIndexer::SearchInPathOnImplSequence, this,
-               file_system_path, query, callback));
+               file_system_path, query, std::move(callback)));
 }
 
 void DevToolsFileSystemIndexer::SearchInPathOnImplSequence(
     const std::string& file_system_path,
     const std::string& query,
-    const SearchCallback& callback) {
+    SearchCallback callback) {
   DCHECK(impl_task_runner()->RunsTasksInCurrentSequence());
   vector<FilePath> file_paths = g_trigram_index.Get().Search(query);
   vector<string> result;
@@ -515,5 +515,5 @@
       result.push_back(it->AsUTF8Unsafe());
   }
   content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE, BindOnce(callback, std::move(result)));
+      FROM_HERE, BindOnce(std::move(callback), std::move(result)));
 }
diff --git a/chrome/browser/devtools/devtools_file_system_indexer.h b/chrome/browser/devtools/devtools_file_system_indexer.h
index 97ce997c..58c03da 100644
--- a/chrome/browser/devtools/devtools_file_system_indexer.h
+++ b/chrome/browser/devtools/devtools_file_system_indexer.h
@@ -27,10 +27,10 @@
     : public base::RefCountedThreadSafe<DevToolsFileSystemIndexer> {
  public:
 
-  typedef base::Callback<void(int)> TotalWorkCallback;
-  typedef base::Callback<void(int)> WorkedCallback;
-  typedef base::Callback<void()> DoneCallback;
-  typedef base::Callback<void(const std::vector<std::string>&)> SearchCallback;
+  typedef base::OnceCallback<void(int)> TotalWorkCallback;
+  typedef base::RepeatingCallback<void(int)> WorkedCallback;
+  typedef base::OnceCallback<void()> DoneCallback;
+  typedef base::OnceCallback<void(const std::vector<std::string>&)> SearchCallback;
 
   class FileSystemIndexingJob
       : public base::RefCountedThreadSafe<FileSystemIndexingJob> {
@@ -42,9 +42,9 @@
     friend class DevToolsFileSystemIndexer;
     FileSystemIndexingJob(const base::FilePath& file_system_path,
                           const std::vector<base::FilePath>& excluded_folders,
-                          const TotalWorkCallback& total_work_callback,
+                          TotalWorkCallback total_work_callback,
                           const WorkedCallback& worked_callback,
-                          const DoneCallback& done_callback);
+                          DoneCallback done_callback);
     virtual ~FileSystemIndexingJob();
 
     void Start();
@@ -88,14 +88,14 @@
   scoped_refptr<FileSystemIndexingJob> IndexPath(
       const std::string& file_system_path,
       const std::vector<std::string>& excluded_folders,
-      const TotalWorkCallback& total_work_callback,
+      TotalWorkCallback total_work_callback,
       const WorkedCallback& worked_callback,
-      const DoneCallback& done_callback);
+      DoneCallback done_callback);
 
   // Performs trigram search for given |query| in |file_system_path|.
   void SearchInPath(const std::string& file_system_path,
                     const std::string& query,
-                    const SearchCallback& callback);
+                    SearchCallback callback);
 
  private:
   friend class base::RefCountedThreadSafe<DevToolsFileSystemIndexer>;
@@ -104,7 +104,7 @@
 
   void SearchInPathOnImplSequence(const std::string& file_system_path,
                                   const std::string& query,
-                                  const SearchCallback& callback);
+                                  SearchCallback callback);
 
   DISALLOW_COPY_AND_ASSIGN(DevToolsFileSystemIndexer);
 };
diff --git a/chrome/browser/devtools/devtools_file_system_indexer_unittest.cc b/chrome/browser/devtools/devtools_file_system_indexer_unittest.cc
index f2403b4d..83bac875 100644
--- a/chrome/browser/devtools/devtools_file_system_indexer_unittest.cc
+++ b/chrome/browser/devtools/devtools_file_system_indexer_unittest.cc
@@ -53,16 +53,16 @@
   scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob> job =
       indexer_->IndexPath(index_path.AsUTF8Unsafe(), excluded_folders,
                           base::DoNothing(), base::DoNothing(),
-                          base::Bind(&DevToolsFileSystemIndexerTest::SetDone,
-                                     base::Unretained(this)));
+                          base::BindOnce(&DevToolsFileSystemIndexerTest::SetDone,
+                                         base::Unretained(this)));
 
   base::RunLoop().Run();
   ASSERT_TRUE(indexing_done_);
 
   indexer_->SearchInPath(
       index_path.AsUTF8Unsafe(), "Hello",
-      base::Bind(&DevToolsFileSystemIndexerTest::SearchCallback,
-                 base::Unretained(this)));
+      base::BindOnce(&DevToolsFileSystemIndexerTest::SearchCallback,
+                     base::Unretained(this)));
   base::RunLoop().Run();
 
   ASSERT_EQ(3lu, search_results_.size());
@@ -72,8 +72,8 @@
 
   indexer_->SearchInPath(
       index_path.AsUTF8Unsafe(), "FUNCTION",
-      base::Bind(&DevToolsFileSystemIndexerTest::SearchCallback,
-                 base::Unretained(this)));
+      base::BindOnce(&DevToolsFileSystemIndexerTest::SearchCallback,
+                     base::Unretained(this)));
   base::RunLoop().Run();
 
   ASSERT_EQ(1lu, search_results_.size());
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index 86f96552..be05158d 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -1264,15 +1264,17 @@
 
   RenderFrameHost* devtools_extension_a_devtools_rfh =
       content::FrameMatchingPredicate(
-          main_web_contents(), base::Bind(&content::FrameHasSourceUrl,
-                                          devtools_a_extension->GetResourceURL(
-                                              "/panel_devtools_page.html")));
+          main_web_contents(),
+          base::BindRepeating(&content::FrameHasSourceUrl,
+                              devtools_a_extension->GetResourceURL(
+                                  "/panel_devtools_page.html")));
   EXPECT_TRUE(devtools_extension_a_devtools_rfh);
   RenderFrameHost* devtools_extension_b_devtools_rfh =
       content::FrameMatchingPredicate(
-          main_web_contents(), base::Bind(&content::FrameHasSourceUrl,
-                                          devtools_b_extension->GetResourceURL(
-                                              "/simple_devtools_page.html")));
+          main_web_contents(),
+          base::BindRepeating(&content::FrameHasSourceUrl,
+                              devtools_b_extension->GetResourceURL(
+                                  "/simple_devtools_page.html")));
   EXPECT_TRUE(devtools_extension_b_devtools_rfh);
 
   RenderFrameHost* devtools_extension_a_panel_rfh =
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index 8a6bcb82..c0176c6 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -1032,15 +1032,15 @@
       scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>(
           file_system_indexer_->IndexPath(
               file_system_path, excluded_folders,
-              Bind(&DevToolsUIBindings::IndexingTotalWorkCalculated,
-                   weak_factory_.GetWeakPtr(), index_request_id,
-                   file_system_path),
-              Bind(&DevToolsUIBindings::IndexingWorked,
-                   weak_factory_.GetWeakPtr(), index_request_id,
-                   file_system_path),
-              Bind(&DevToolsUIBindings::IndexingDone,
-                   weak_factory_.GetWeakPtr(), index_request_id,
-                   file_system_path)));
+              BindOnce(&DevToolsUIBindings::IndexingTotalWorkCalculated,
+                       weak_factory_.GetWeakPtr(), index_request_id,
+                       file_system_path),
+              BindRepeating(&DevToolsUIBindings::IndexingWorked,
+                       weak_factory_.GetWeakPtr(), index_request_id,
+                       file_system_path),
+              BindOnce(&DevToolsUIBindings::IndexingDone,
+                       weak_factory_.GetWeakPtr(), index_request_id,
+                       file_system_path)));
 }
 
 void DevToolsUIBindings::StopIndexing(int index_request_id) {
@@ -1065,10 +1065,10 @@
   }
   file_system_indexer_->SearchInPath(file_system_path,
                                      query,
-                                     Bind(&DevToolsUIBindings::SearchCompleted,
-                                          weak_factory_.GetWeakPtr(),
-                                          search_request_id,
-                                          file_system_path));
+                                     BindOnce(&DevToolsUIBindings::SearchCompleted,
+                                              weak_factory_.GetWeakPtr(),
+                                              search_request_id,
+                                              file_system_path));
 }
 
 void DevToolsUIBindings::SetWhitelistedShortcuts(const std::string& message) {
diff --git a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc
index d310022..a76cb5b 100644
--- a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc
+++ b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc
@@ -52,7 +52,7 @@
 }
 
 ActivityLogAPI::ActivityLogAPI(content::BrowserContext* context)
-    : browser_context_(context), initialized_(false) {
+    : browser_context_(context) {
   if (!EventRouter::Get(browser_context_)) {  // Check for testing.
     DVLOG(1) << "ExtensionSystem event_router does not exist.";
     return;
@@ -65,9 +65,6 @@
   initialized_ = true;
 }
 
-ActivityLogAPI::~ActivityLogAPI() {
-}
-
 void ActivityLogAPI::Shutdown() {
   if (!initialized_) {  // Check for testing.
     DVLOG(1) << "ExtensionSystem event_router does not exist.";
diff --git a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h
index df2849b..8df0861 100644
--- a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h
+++ b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h
@@ -9,7 +9,10 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_ACTIVITY_LOG_PRIVATE_ACTIVITY_LOG_PRIVATE_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_ACTIVITY_LOG_PRIVATE_ACTIVITY_LOG_PRIVATE_API_H_
 
-#include "base/macros.h"
+#include <memory>
+#include <string>
+#include <vector>
+
 #include "base/synchronization/lock.h"
 #include "chrome/browser/extensions/activity_log/activity_actions.h"
 #include "chrome/browser/extensions/activity_log/activity_log.h"
@@ -27,7 +30,9 @@
                        public EventRouter::Observer {
  public:
   explicit ActivityLogAPI(content::BrowserContext* context);
-  ~ActivityLogAPI() override;
+  ActivityLogAPI(const ActivityLogAPI&) = delete;
+  ActivityLogAPI& operator=(const ActivityLogAPI&) = delete;
+  ~ActivityLogAPI() override = default;
 
   // BrowserContextKeyedAPI implementation.
   static BrowserContextKeyedAPIFactory<ActivityLogAPI>* GetFactoryInstance();
@@ -54,9 +59,7 @@
 
   content::BrowserContext* browser_context_;
   ActivityLog* activity_log_;
-  bool initialized_;
-
-  DISALLOW_COPY_AND_ASSIGN(ActivityLogAPI);
+  bool initialized_ = false;
 };
 
 template <>
diff --git a/chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_apitest.cc b/chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_apitest.cc
index f45f9a8..d00b5b8 100644
--- a/chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_apitest.cc
+++ b/chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_apitest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/macros.h"
 #include "base/test/gmock_callback_support.h"
 #include "base/test/mock_callback.h"
 #include "base/values.h"
@@ -41,6 +40,10 @@
 class AutofillAssistantPrivateApiTest : public ExtensionApiTest {
  public:
   AutofillAssistantPrivateApiTest() = default;
+  AutofillAssistantPrivateApiTest(const AutofillAssistantPrivateApiTest&) =
+      delete;
+  AutofillAssistantPrivateApiTest& operator=(
+      const AutofillAssistantPrivateApiTest&) = delete;
 
   void SetUpOnMainThread() override {
     ExtensionApiTest::SetUpOnMainThread();
@@ -82,8 +85,6 @@
  private:
   std::unique_ptr<MockService> service_;
   MockService* mock_service_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillAssistantPrivateApiTest);
 };
 
 IN_PROC_BROWSER_TEST_F(AutofillAssistantPrivateApiTest, DefaultTest) {
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
index 15a0d0e..d105975 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
@@ -93,11 +93,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // AutofillPrivateSaveAddressFunction
 
-AutofillPrivateSaveAddressFunction::AutofillPrivateSaveAddressFunction()
-    : chrome_details_(this) {}
-
-AutofillPrivateSaveAddressFunction::~AutofillPrivateSaveAddressFunction() {}
-
 ExtensionFunction::ResponseAction AutofillPrivateSaveAddressFunction::Run() {
   std::unique_ptr<api::autofill_private::SaveAddress::Params> parameters =
       api::autofill_private::SaveAddress::Params::Create(*args_);
@@ -206,12 +201,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // AutofillPrivateGetCountryListFunction
 
-AutofillPrivateGetCountryListFunction::AutofillPrivateGetCountryListFunction()
-    : chrome_details_(this) {}
-
-AutofillPrivateGetCountryListFunction::
-    ~AutofillPrivateGetCountryListFunction() {}
-
 ExtensionFunction::ResponseAction AutofillPrivateGetCountryListFunction::Run() {
   autofill::PersonalDataManager* personal_data =
       autofill::PersonalDataManagerFactory::GetForProfile(
@@ -234,9 +223,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // AutofillPrivateGetAddressComponentsFunction
 
-AutofillPrivateGetAddressComponentsFunction::
-    ~AutofillPrivateGetAddressComponentsFunction() {}
-
 ExtensionFunction::ResponseAction
 AutofillPrivateGetAddressComponentsFunction::Run() {
   std::unique_ptr<api::autofill_private::GetAddressComponents::Params>
@@ -271,12 +257,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // AutofillPrivateGetAddressListFunction
 
-AutofillPrivateGetAddressListFunction::AutofillPrivateGetAddressListFunction()
-    : chrome_details_(this) {}
-
-AutofillPrivateGetAddressListFunction::
-    ~AutofillPrivateGetAddressListFunction() {}
-
 ExtensionFunction::ResponseAction AutofillPrivateGetAddressListFunction::Run() {
   autofill::PersonalDataManager* personal_data =
       autofill::PersonalDataManagerFactory::GetForProfile(
@@ -293,12 +273,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // AutofillPrivateSaveCreditCardFunction
 
-AutofillPrivateSaveCreditCardFunction::AutofillPrivateSaveCreditCardFunction()
-    : chrome_details_(this) {}
-
-AutofillPrivateSaveCreditCardFunction::
-    ~AutofillPrivateSaveCreditCardFunction() {}
-
 ExtensionFunction::ResponseAction AutofillPrivateSaveCreditCardFunction::Run() {
   std::unique_ptr<api::autofill_private::SaveCreditCard::Params> parameters =
       api::autofill_private::SaveCreditCard::Params::Create(*args_);
@@ -380,11 +354,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // AutofillPrivateRemoveEntryFunction
 
-AutofillPrivateRemoveEntryFunction::AutofillPrivateRemoveEntryFunction()
-    : chrome_details_(this) {}
-
-AutofillPrivateRemoveEntryFunction::~AutofillPrivateRemoveEntryFunction() {}
-
 ExtensionFunction::ResponseAction AutofillPrivateRemoveEntryFunction::Run() {
   std::unique_ptr<api::autofill_private::RemoveEntry::Params> parameters =
       api::autofill_private::RemoveEntry::Params::Create(*args_);
@@ -404,9 +373,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // AutofillPrivateValidatePhoneNumbersFunction
 
-AutofillPrivateValidatePhoneNumbersFunction::
-    ~AutofillPrivateValidatePhoneNumbersFunction() {}
-
 ExtensionFunction::ResponseAction
 AutofillPrivateValidatePhoneNumbersFunction::Run() {
   std::unique_ptr<api::autofill_private::ValidatePhoneNumbers::Params>
@@ -429,12 +395,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // AutofillPrivateMaskCreditCardFunction
 
-AutofillPrivateMaskCreditCardFunction::AutofillPrivateMaskCreditCardFunction()
-    : chrome_details_(this) {}
-
-AutofillPrivateMaskCreditCardFunction::
-    ~AutofillPrivateMaskCreditCardFunction() {}
-
 ExtensionFunction::ResponseAction AutofillPrivateMaskCreditCardFunction::Run() {
   std::unique_ptr<api::autofill_private::MaskCreditCard::Params> parameters =
       api::autofill_private::MaskCreditCard::Params::Create(*args_);
@@ -454,13 +414,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // AutofillPrivateGetCreditCardListFunction
 
-AutofillPrivateGetCreditCardListFunction::
-    AutofillPrivateGetCreditCardListFunction()
-    : chrome_details_(this) {}
-
-AutofillPrivateGetCreditCardListFunction::
-    ~AutofillPrivateGetCreditCardListFunction() {}
-
 ExtensionFunction::ResponseAction
 AutofillPrivateGetCreditCardListFunction::Run() {
   autofill::PersonalDataManager* personal_data =
@@ -479,13 +432,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // AutofillPrivateMigrateCreditCardsFunction
 
-AutofillPrivateMigrateCreditCardsFunction::
-    AutofillPrivateMigrateCreditCardsFunction()
-    : chrome_details_(this) {}
-
-AutofillPrivateMigrateCreditCardsFunction::
-    ~AutofillPrivateMigrateCreditCardsFunction() {}
-
 ExtensionFunction::ResponseAction
 AutofillPrivateMigrateCreditCardsFunction::Run() {
   autofill::PersonalDataManager* personal_data =
@@ -525,13 +471,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // AutofillPrivateLogServerCardLinkClickedFunction
 
-AutofillPrivateLogServerCardLinkClickedFunction::
-    AutofillPrivateLogServerCardLinkClickedFunction()
-    : chrome_details_(this) {}
-
-AutofillPrivateLogServerCardLinkClickedFunction::
-    ~AutofillPrivateLogServerCardLinkClickedFunction() {}
-
 ExtensionFunction::ResponseAction
 AutofillPrivateLogServerCardLinkClickedFunction::Run() {
   autofill::PersonalDataManager* personal_data =
@@ -548,13 +487,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction
 
-AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction::
-    AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction()
-    : chrome_details_(this) {}
-
-AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction::
-    ~AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction() {}
-
 ExtensionFunction::ResponseAction
 AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction::Run() {
   // Getting CreditCardAccessManager from WebContents.
@@ -581,12 +513,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // AutofillPrivateGetUpiIdListFunction
 
-AutofillPrivateGetUpiIdListFunction::AutofillPrivateGetUpiIdListFunction() =
-    default;
-
-AutofillPrivateGetUpiIdListFunction::~AutofillPrivateGetUpiIdListFunction() =
-    default;
-
 ExtensionFunction::ResponseAction AutofillPrivateGetUpiIdListFunction::Run() {
   autofill::PersonalDataManager* personal_data =
       autofill::PersonalDataManagerFactory::GetForProfile(
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_api.h b/chrome/browser/extensions/api/autofill_private/autofill_private_api.h
index 64e5518..138c0c3 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_private_api.h
+++ b/chrome/browser/extensions/api/autofill_private/autofill_private_api.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/macros.h"
 #include "chrome/browser/extensions/chrome_extension_function_details.h"
 #include "extensions/browser/extension_function.h"
 
@@ -15,236 +14,260 @@
 
 class AutofillPrivateSaveAddressFunction : public ExtensionFunction {
  public:
-  AutofillPrivateSaveAddressFunction();
+  AutofillPrivateSaveAddressFunction() = default;
+  AutofillPrivateSaveAddressFunction(
+      const AutofillPrivateSaveAddressFunction&) = delete;
+  AutofillPrivateSaveAddressFunction& operator=(
+      const AutofillPrivateSaveAddressFunction&) = delete;
   DECLARE_EXTENSION_FUNCTION("autofillPrivate.saveAddress",
                              AUTOFILLPRIVATE_SAVEADDRESS)
 
  protected:
-  ~AutofillPrivateSaveAddressFunction() override;
-
-  // ExtensionFunction overrides.
-  ResponseAction Run() override;
-
- private:
-  ChromeExtensionFunctionDetails chrome_details_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateSaveAddressFunction);
-};
-
-class AutofillPrivateGetCountryListFunction : public ExtensionFunction {
- public:
-  AutofillPrivateGetCountryListFunction();
-  DECLARE_EXTENSION_FUNCTION("autofillPrivate.getCountryList",
-                             AUTOFILLPRIVATE_GETCOUNTRYLIST)
-
- protected:
-  ~AutofillPrivateGetCountryListFunction() override;
-
-  // ExtensionFunction overrides.
-  ResponseAction Run() override;
-
- private:
-  ChromeExtensionFunctionDetails chrome_details_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateGetCountryListFunction);
-};
-
-class AutofillPrivateGetAddressComponentsFunction : public ExtensionFunction {
- public:
-  AutofillPrivateGetAddressComponentsFunction() {}
-  DECLARE_EXTENSION_FUNCTION("autofillPrivate.getAddressComponents",
-                             AUTOFILLPRIVATE_GETADDRESSCOMPONENTS)
-
- protected:
-  ~AutofillPrivateGetAddressComponentsFunction() override;
-
-  // ExtensionFunction overrides.
-  ResponseAction Run() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateGetAddressComponentsFunction);
-};
-
-class AutofillPrivateGetAddressListFunction : public ExtensionFunction {
- public:
-  AutofillPrivateGetAddressListFunction();
-  DECLARE_EXTENSION_FUNCTION("autofillPrivate.getAddressList",
-                             AUTOFILLPRIVATE_GETADDRESSLIST)
-
- protected:
-  ~AutofillPrivateGetAddressListFunction() override;
-
-  // ExtensionFunction overrides.
-  ResponseAction Run() override;
-
- private:
-  ChromeExtensionFunctionDetails chrome_details_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateGetAddressListFunction);
-};
-
-class AutofillPrivateSaveCreditCardFunction : public ExtensionFunction {
- public:
-  AutofillPrivateSaveCreditCardFunction();
-  DECLARE_EXTENSION_FUNCTION("autofillPrivate.saveCreditCard",
-                             AUTOFILLPRIVATE_SAVECREDITCARD)
-
- protected:
-  ~AutofillPrivateSaveCreditCardFunction() override;
-
-  // ExtensionFunction overrides.
-  ResponseAction Run() override;
-
- private:
-  ChromeExtensionFunctionDetails chrome_details_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateSaveCreditCardFunction);
-};
-
-class AutofillPrivateRemoveEntryFunction : public ExtensionFunction {
- public:
-  AutofillPrivateRemoveEntryFunction();
-  DECLARE_EXTENSION_FUNCTION("autofillPrivate.removeEntry",
-                             AUTOFILLPRIVATE_REMOVEENTRY)
-
- protected:
-  ~AutofillPrivateRemoveEntryFunction() override;
-
-  // ExtensionFunction overrides.
-  ResponseAction Run() override;
-
- private:
-  ChromeExtensionFunctionDetails chrome_details_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateRemoveEntryFunction);
-};
-
-class AutofillPrivateValidatePhoneNumbersFunction : public ExtensionFunction {
- public:
-  AutofillPrivateValidatePhoneNumbersFunction() {}
-  DECLARE_EXTENSION_FUNCTION("autofillPrivate.validatePhoneNumbers",
-                             AUTOFILLPRIVATE_VALIDATEPHONENUMBERS)
-
- protected:
-  ~AutofillPrivateValidatePhoneNumbersFunction() override;
-
-  // ExtensionFunction overrides.
-  ResponseAction Run() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateValidatePhoneNumbersFunction);
-};
-
-class AutofillPrivateMaskCreditCardFunction : public ExtensionFunction {
- public:
-  AutofillPrivateMaskCreditCardFunction();
-  DECLARE_EXTENSION_FUNCTION("autofillPrivate.maskCreditCard",
-                             AUTOFILLPRIVATE_MASKCREDITCARD)
-
- protected:
-  ~AutofillPrivateMaskCreditCardFunction() override;
-
-  // ExtensionFunction overrides.
-  ResponseAction Run() override;
-
- private:
-  ChromeExtensionFunctionDetails chrome_details_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateMaskCreditCardFunction);
-};
-
-class AutofillPrivateGetCreditCardListFunction : public ExtensionFunction {
- public:
-  AutofillPrivateGetCreditCardListFunction();
-  DECLARE_EXTENSION_FUNCTION("autofillPrivate.getCreditCardList",
-                             AUTOFILLPRIVATE_GETCREDITCARDLIST)
-
- protected:
-  ~AutofillPrivateGetCreditCardListFunction() override;
-
-  // ExtensionFunction overrides.
-  ResponseAction Run() override;
-
- private:
-  ChromeExtensionFunctionDetails chrome_details_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateGetCreditCardListFunction);
-};
-
-class AutofillPrivateMigrateCreditCardsFunction : public ExtensionFunction {
- public:
-  AutofillPrivateMigrateCreditCardsFunction();
-  DECLARE_EXTENSION_FUNCTION("autofillPrivate.migrateCreditCards",
-                             AUTOFILLPRIVATE_MIGRATECREDITCARDS)
-
- protected:
-  ~AutofillPrivateMigrateCreditCardsFunction() override;
-
-  // ExtensionFunction overrides.
-  ResponseAction Run() override;
-
- private:
-  ChromeExtensionFunctionDetails chrome_details_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateMigrateCreditCardsFunction);
-};
-
-class AutofillPrivateLogServerCardLinkClickedFunction
-    : public ExtensionFunction {
- public:
-  AutofillPrivateLogServerCardLinkClickedFunction();
-  DECLARE_EXTENSION_FUNCTION("autofillPrivate.logServerCardLinkClicked",
-                             AUTOFILLPRIVATE_SERVERCARDLINKCLICKED)
-
- protected:
-  ~AutofillPrivateLogServerCardLinkClickedFunction() override;
-
-  // ExtensionFunction overrides.
-  ResponseAction Run() override;
-
- private:
-  ChromeExtensionFunctionDetails chrome_details_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateLogServerCardLinkClickedFunction);
-};
-
-class AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction
-    : public ExtensionFunction {
- public:
-  AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction();
-  DECLARE_EXTENSION_FUNCTION(
-      "autofillPrivate.setCreditCardFIDOAuthEnabledState",
-      AUTOFILLPRIVATE_SETCREDITCARDFIDOAUTHENABLEDSTATE)
-
- protected:
-  ~AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction() override;
-
-  // ExtensionFunction overrides.
-  ResponseAction Run() override;
-
- private:
-  ChromeExtensionFunctionDetails chrome_details_;
-
-  DISALLOW_COPY_AND_ASSIGN(
-      AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction);
-};
-
-class AutofillPrivateGetUpiIdListFunction : public ExtensionFunction {
- public:
-  AutofillPrivateGetUpiIdListFunction();
-  DECLARE_EXTENSION_FUNCTION("autofillPrivate.getUpiIdList",
-                             AUTOFILLPRIVATE_GETUPIIDLIST)
-
- protected:
-  ~AutofillPrivateGetUpiIdListFunction() override;
+  ~AutofillPrivateSaveAddressFunction() override = default;
 
   // ExtensionFunction overrides.
   ResponseAction Run() override;
 
  private:
   ChromeExtensionFunctionDetails chrome_details_{this};
+};
 
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateGetUpiIdListFunction);
+class AutofillPrivateGetCountryListFunction : public ExtensionFunction {
+ public:
+  AutofillPrivateGetCountryListFunction() = default;
+  AutofillPrivateGetCountryListFunction(
+      const AutofillPrivateGetCountryListFunction&) = delete;
+  AutofillPrivateGetCountryListFunction& operator=(
+      const AutofillPrivateGetCountryListFunction&) = delete;
+  DECLARE_EXTENSION_FUNCTION("autofillPrivate.getCountryList",
+                             AUTOFILLPRIVATE_GETCOUNTRYLIST)
+
+ protected:
+  ~AutofillPrivateGetCountryListFunction() override = default;
+
+  // ExtensionFunction overrides.
+  ResponseAction Run() override;
+
+ private:
+  ChromeExtensionFunctionDetails chrome_details_{this};
+};
+
+class AutofillPrivateGetAddressComponentsFunction : public ExtensionFunction {
+ public:
+  AutofillPrivateGetAddressComponentsFunction() = default;
+  AutofillPrivateGetAddressComponentsFunction(
+      const AutofillPrivateGetAddressComponentsFunction&) = delete;
+  AutofillPrivateGetAddressComponentsFunction& operator=(
+      const AutofillPrivateGetAddressComponentsFunction&) = delete;
+  DECLARE_EXTENSION_FUNCTION("autofillPrivate.getAddressComponents",
+                             AUTOFILLPRIVATE_GETADDRESSCOMPONENTS)
+
+ protected:
+  ~AutofillPrivateGetAddressComponentsFunction() override = default;
+
+  // ExtensionFunction overrides.
+  ResponseAction Run() override;
+};
+
+class AutofillPrivateGetAddressListFunction : public ExtensionFunction {
+ public:
+  AutofillPrivateGetAddressListFunction() = default;
+  AutofillPrivateGetAddressListFunction(
+      const AutofillPrivateGetAddressListFunction&) = delete;
+  AutofillPrivateGetAddressListFunction& operator=(
+      const AutofillPrivateGetAddressListFunction&) = delete;
+  DECLARE_EXTENSION_FUNCTION("autofillPrivate.getAddressList",
+                             AUTOFILLPRIVATE_GETADDRESSLIST)
+
+ protected:
+  ~AutofillPrivateGetAddressListFunction() override = default;
+
+  // ExtensionFunction overrides.
+  ResponseAction Run() override;
+
+ private:
+  ChromeExtensionFunctionDetails chrome_details_{this};
+};
+
+class AutofillPrivateSaveCreditCardFunction : public ExtensionFunction {
+ public:
+  AutofillPrivateSaveCreditCardFunction() = default;
+  AutofillPrivateSaveCreditCardFunction(
+      const AutofillPrivateSaveCreditCardFunction&) = delete;
+  AutofillPrivateSaveCreditCardFunction& operator=(
+      const AutofillPrivateSaveCreditCardFunction&) = delete;
+  DECLARE_EXTENSION_FUNCTION("autofillPrivate.saveCreditCard",
+                             AUTOFILLPRIVATE_SAVECREDITCARD)
+
+ protected:
+  ~AutofillPrivateSaveCreditCardFunction() override = default;
+
+  // ExtensionFunction overrides.
+  ResponseAction Run() override;
+
+ private:
+  ChromeExtensionFunctionDetails chrome_details_{this};
+};
+
+class AutofillPrivateRemoveEntryFunction : public ExtensionFunction {
+ public:
+  AutofillPrivateRemoveEntryFunction() = default;
+  AutofillPrivateRemoveEntryFunction(
+      const AutofillPrivateRemoveEntryFunction&) = delete;
+  AutofillPrivateRemoveEntryFunction& operator=(
+      const AutofillPrivateRemoveEntryFunction&) = delete;
+  DECLARE_EXTENSION_FUNCTION("autofillPrivate.removeEntry",
+                             AUTOFILLPRIVATE_REMOVEENTRY)
+
+ protected:
+  ~AutofillPrivateRemoveEntryFunction() override = default;
+
+  // ExtensionFunction overrides.
+  ResponseAction Run() override;
+
+ private:
+  ChromeExtensionFunctionDetails chrome_details_{this};
+};
+
+class AutofillPrivateValidatePhoneNumbersFunction : public ExtensionFunction {
+ public:
+  AutofillPrivateValidatePhoneNumbersFunction() = default;
+  AutofillPrivateValidatePhoneNumbersFunction(
+      const AutofillPrivateValidatePhoneNumbersFunction&) = delete;
+  AutofillPrivateValidatePhoneNumbersFunction& operator=(
+      const AutofillPrivateValidatePhoneNumbersFunction&) = delete;
+  DECLARE_EXTENSION_FUNCTION("autofillPrivate.validatePhoneNumbers",
+                             AUTOFILLPRIVATE_VALIDATEPHONENUMBERS)
+
+ protected:
+  ~AutofillPrivateValidatePhoneNumbersFunction() override = default;
+
+  // ExtensionFunction overrides.
+  ResponseAction Run() override;
+};
+
+class AutofillPrivateMaskCreditCardFunction : public ExtensionFunction {
+ public:
+  AutofillPrivateMaskCreditCardFunction() = default;
+  AutofillPrivateMaskCreditCardFunction(
+      const AutofillPrivateMaskCreditCardFunction&) = delete;
+  AutofillPrivateMaskCreditCardFunction& operator=(
+      const AutofillPrivateMaskCreditCardFunction&) = delete;
+  DECLARE_EXTENSION_FUNCTION("autofillPrivate.maskCreditCard",
+                             AUTOFILLPRIVATE_MASKCREDITCARD)
+
+ protected:
+  ~AutofillPrivateMaskCreditCardFunction() override = default;
+
+  // ExtensionFunction overrides.
+  ResponseAction Run() override;
+
+ private:
+  ChromeExtensionFunctionDetails chrome_details_{this};
+};
+
+class AutofillPrivateGetCreditCardListFunction : public ExtensionFunction {
+ public:
+  AutofillPrivateGetCreditCardListFunction() = default;
+  AutofillPrivateGetCreditCardListFunction(
+      const AutofillPrivateGetCreditCardListFunction&) = delete;
+  AutofillPrivateGetCreditCardListFunction& operator=(
+      const AutofillPrivateGetCreditCardListFunction&) = delete;
+  DECLARE_EXTENSION_FUNCTION("autofillPrivate.getCreditCardList",
+                             AUTOFILLPRIVATE_GETCREDITCARDLIST)
+
+ protected:
+  ~AutofillPrivateGetCreditCardListFunction() override = default;
+
+  // ExtensionFunction overrides.
+  ResponseAction Run() override;
+
+ private:
+  ChromeExtensionFunctionDetails chrome_details_{this};
+};
+
+class AutofillPrivateMigrateCreditCardsFunction : public ExtensionFunction {
+ public:
+  AutofillPrivateMigrateCreditCardsFunction() = default;
+  AutofillPrivateMigrateCreditCardsFunction(
+      const AutofillPrivateMigrateCreditCardsFunction&) = delete;
+  AutofillPrivateMigrateCreditCardsFunction& operator=(
+      const AutofillPrivateMigrateCreditCardsFunction&) = delete;
+  DECLARE_EXTENSION_FUNCTION("autofillPrivate.migrateCreditCards",
+                             AUTOFILLPRIVATE_MIGRATECREDITCARDS)
+
+ protected:
+  ~AutofillPrivateMigrateCreditCardsFunction() override = default;
+
+  // ExtensionFunction overrides.
+  ResponseAction Run() override;
+
+ private:
+  ChromeExtensionFunctionDetails chrome_details_{this};
+};
+
+class AutofillPrivateLogServerCardLinkClickedFunction
+    : public ExtensionFunction {
+ public:
+  AutofillPrivateLogServerCardLinkClickedFunction() = default;
+  AutofillPrivateLogServerCardLinkClickedFunction(
+      const AutofillPrivateLogServerCardLinkClickedFunction&) = delete;
+  AutofillPrivateLogServerCardLinkClickedFunction& operator=(
+      const AutofillPrivateLogServerCardLinkClickedFunction&) = delete;
+  DECLARE_EXTENSION_FUNCTION("autofillPrivate.logServerCardLinkClicked",
+                             AUTOFILLPRIVATE_SERVERCARDLINKCLICKED)
+
+ protected:
+  ~AutofillPrivateLogServerCardLinkClickedFunction() override = default;
+
+  // ExtensionFunction overrides.
+  ResponseAction Run() override;
+
+ private:
+  ChromeExtensionFunctionDetails chrome_details_{this};
+};
+
+class AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction
+    : public ExtensionFunction {
+ public:
+  AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction() = default;
+  AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction(
+      const AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction&) = delete;
+  AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction& operator=(
+      const AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction&) = delete;
+  DECLARE_EXTENSION_FUNCTION(
+      "autofillPrivate.setCreditCardFIDOAuthEnabledState",
+      AUTOFILLPRIVATE_SETCREDITCARDFIDOAUTHENABLEDSTATE)
+
+ protected:
+  ~AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction() override =
+      default;
+
+  // ExtensionFunction overrides.
+  ResponseAction Run() override;
+
+ private:
+  ChromeExtensionFunctionDetails chrome_details_{this};
+};
+
+class AutofillPrivateGetUpiIdListFunction : public ExtensionFunction {
+ public:
+  AutofillPrivateGetUpiIdListFunction() = default;
+  AutofillPrivateGetUpiIdListFunction(
+      const AutofillPrivateGetUpiIdListFunction&) = delete;
+  AutofillPrivateGetUpiIdListFunction& operator=(
+      const AutofillPrivateGetUpiIdListFunction&) = delete;
+  DECLARE_EXTENSION_FUNCTION("autofillPrivate.getUpiIdList",
+                             AUTOFILLPRIVATE_GETUPIIDLIST)
+
+ protected:
+  ~AutofillPrivateGetUpiIdListFunction() override = default;
+
+  // ExtensionFunction overrides.
+  ResponseAction Run() override;
+
+ private:
+  ChromeExtensionFunctionDetails chrome_details_{this};
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc
index 48da5f15..c93b58a8 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
-#include "base/macros.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/common/extensions/api/autofill_private.h"
@@ -18,8 +17,10 @@
 
 class AutofillPrivateApiTest : public ExtensionApiTest {
  public:
-  AutofillPrivateApiTest() {}
-  ~AutofillPrivateApiTest() override {}
+  AutofillPrivateApiTest() = default;
+  AutofillPrivateApiTest(const AutofillPrivateApiTest&) = delete;
+  AutofillPrivateApiTest& operator=(const AutofillPrivateApiTest&) = delete;
+  ~AutofillPrivateApiTest() override = default;
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     ExtensionApiTest::SetUpCommandLine(command_line);
@@ -35,9 +36,6 @@
     return RunExtensionSubtest("autofill_private", "main.html?" + subtest,
                                kFlagNone, kFlagLoadAsComponent);
   }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateApiTest);
 };
 
 }  // namespace
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.cc
index dc419d2..ee5b96a1 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h"
 
+#include <memory>
 #include <utility>
 #include <vector>
 
@@ -23,9 +24,7 @@
 
 AutofillPrivateEventRouter::AutofillPrivateEventRouter(
     content::BrowserContext* context)
-    : context_(context),
-      event_router_(nullptr),
-      personal_data_(nullptr) {
+    : context_(context) {
   // Register with the event router so we know when renderers are listening to
   // our events. We first check and see if there *is* an event router, because
   // some unit tests try to create all context services, but don't initialize
@@ -42,9 +41,6 @@
   personal_data_->AddObserver(this);
 }
 
-AutofillPrivateEventRouter::~AutofillPrivateEventRouter() {
-}
-
 void AutofillPrivateEventRouter::Shutdown() {
   if (personal_data_)
     personal_data_->RemoveObserver(this);
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h b/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h
index 58236ef..7e8c933 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h
+++ b/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_PRIVATE_AUTOFILL_PRIVATE_EVENT_ROUTER_H_
 #define CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_PRIVATE_AUTOFILL_PRIVATE_EVENT_ROUTER_H_
 
-#include "base/macros.h"
 #include "components/autofill/core/browser/personal_data_manager_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "extensions/browser/event_router.h"
@@ -29,7 +28,10 @@
  public:
   static AutofillPrivateEventRouter* Create(
       content::BrowserContext* browser_context);
-  ~AutofillPrivateEventRouter() override;
+  AutofillPrivateEventRouter(const AutofillPrivateEventRouter&) = delete;
+  AutofillPrivateEventRouter& operator=(const AutofillPrivateEventRouter&) =
+      delete;
+  ~AutofillPrivateEventRouter() override = default;
 
  protected:
   explicit AutofillPrivateEventRouter(content::BrowserContext* context);
@@ -43,11 +45,9 @@
  private:
   content::BrowserContext* context_;
 
-  EventRouter* event_router_;
+  EventRouter* event_router_ = nullptr;
 
-  autofill::PersonalDataManager* personal_data_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateEventRouter);
+  autofill::PersonalDataManager* personal_data_ = nullptr;
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.cc
index b21d4cda..88ea1f7 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.cc
@@ -33,10 +33,6 @@
   DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
 }
 
-AutofillPrivateEventRouterFactory::
-    ~AutofillPrivateEventRouterFactory() {
-}
-
 KeyedService* AutofillPrivateEventRouterFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   return AutofillPrivateEventRouter::Create(context);
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.h b/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.h
index 5856e3b..e5d38f0 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.h
+++ b/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_PRIVATE_AUTOFILL_PRIVATE_EVENT_ROUTER_FACTORY_H_
 #define CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_PRIVATE_AUTOFILL_PRIVATE_EVENT_ROUTER_FACTORY_H_
 
-#include "base/macros.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
@@ -27,6 +26,11 @@
   // Returns the AutofillPrivateEventRouterFactory instance.
   static AutofillPrivateEventRouterFactory* GetInstance();
 
+  AutofillPrivateEventRouterFactory(const AutofillPrivateEventRouterFactory&) =
+      delete;
+  AutofillPrivateEventRouterFactory& operator=(
+      const AutofillPrivateEventRouterFactory&) = delete;
+
  protected:
   // BrowserContextKeyedServiceFactory overrides:
   content::BrowserContext* GetBrowserContextToUse(
@@ -37,13 +41,11 @@
   friend struct base::DefaultSingletonTraits<AutofillPrivateEventRouterFactory>;
 
   AutofillPrivateEventRouterFactory();
-  ~AutofillPrivateEventRouterFactory() override;
+  ~AutofillPrivateEventRouterFactory() override = default;
 
   // BrowserContextKeyedServiceFactory:
   KeyedService* BuildServiceInstanceFor(
       content::BrowserContext* profile) const override;
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillPrivateEventRouterFactory);
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.h b/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.h
index 35e114b..13cba0b 100644
--- a/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.h
+++ b/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_CHROME_AUTOMATION_INTERNAL_API_DELEGATE_H_
 #define CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_CHROME_AUTOMATION_INTERNAL_API_DELEGATE_H_
 
+#include <string>
+
 #include "extensions/browser/api/automation_internal/automation_internal_api_delegate.h"
 
 namespace extensions {
@@ -14,6 +16,10 @@
     : public AutomationInternalApiDelegate {
  public:
   ChromeAutomationInternalApiDelegate();
+  ChromeAutomationInternalApiDelegate(
+      const ChromeAutomationInternalApiDelegate&) = delete;
+  ChromeAutomationInternalApiDelegate& operator=(
+      const ChromeAutomationInternalApiDelegate&) = delete;
   ~ChromeAutomationInternalApiDelegate() override;
 
   bool CanRequestAutomation(const Extension* extension,
@@ -32,8 +38,6 @@
   ui::AXTreeID GetAXTreeID() override;
   void SetEventBundleSink(ui::AXEventBundleSink* sink) override;
   content::BrowserContext* GetActiveUserContext() override;
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeAutomationInternalApiDelegate);
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
index 00ad2b9..1815e6a 100644
--- a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
+++ b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
@@ -205,7 +205,7 @@
     : browser_context_(browser_context) {
 }
 
-BookmarkManagerPrivateAPI::~BookmarkManagerPrivateAPI() {}
+BookmarkManagerPrivateAPI::~BookmarkManagerPrivateAPI() = default;
 
 void BookmarkManagerPrivateAPI::Shutdown() {
   EventRouter::Get(browser_context_)->UnregisterObserver(this);
diff --git a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
index 27e4655b..4067dd53 100644
--- a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
+++ b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
@@ -6,8 +6,9 @@
 #define CHROME_BROWSER_EXTENSIONS_API_BOOKMARK_MANAGER_PRIVATE_BOOKMARK_MANAGER_PRIVATE_API_H_
 
 #include <memory>
+#include <string>
+#include <vector>
 
-#include "base/macros.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/api/bookmarks/bookmarks_api.h"
 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
@@ -95,6 +96,10 @@
  public:
   explicit BookmarkManagerPrivateDragEventRouter(
       content::WebContents* web_contents);
+  BookmarkManagerPrivateDragEventRouter(
+      const BookmarkManagerPrivateDragEventRouter&) = delete;
+  BookmarkManagerPrivateDragEventRouter& operator=(
+      const BookmarkManagerPrivateDragEventRouter&) = delete;
   ~BookmarkManagerPrivateDragEventRouter() override;
 
   // BookmarkTabHelper::BookmarkDrag interface
@@ -123,8 +128,6 @@
   bookmarks::BookmarkNodeData bookmark_drag_data_;
 
   WEB_CONTENTS_USER_DATA_KEY_DECL();
-
-  DISALLOW_COPY_AND_ASSIGN(BookmarkManagerPrivateDragEventRouter);
 };
 
 class ClipboardBookmarkManagerFunction : public extensions::BookmarksFunction {
diff --git a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_unittest.cc b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_unittest.cc
index 8462aa9..205107a9 100644
--- a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_unittest.cc
@@ -18,7 +18,11 @@
 
 class BookmarkManagerPrivateApiUnitTest : public ExtensionServiceTestBase {
  public:
-  BookmarkManagerPrivateApiUnitTest() {}
+  BookmarkManagerPrivateApiUnitTest() = default;
+  BookmarkManagerPrivateApiUnitTest(const BookmarkManagerPrivateApiUnitTest&) =
+      delete;
+  BookmarkManagerPrivateApiUnitTest& operator=(
+      const BookmarkManagerPrivateApiUnitTest&) = delete;
 
   void SetUp() override {
     ExtensionServiceTestBase::SetUp();
@@ -43,8 +47,6 @@
  private:
   bookmarks::BookmarkModel* model_ = nullptr;
   std::string node_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(BookmarkManagerPrivateApiUnitTest);
 };
 
 // Tests that running ExtensionFunction-s on deleted bookmark node gracefully
diff --git a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
index 2e7f7b82..3cea597 100644
--- a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
+++ b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 
+#include <limits>
 #include <memory>
 #include <utility>
 
diff --git a/chrome/browser/extensions/api/bookmarks/bookmarks_api.h b/chrome/browser/extensions/api/bookmarks/bookmarks_api.h
index 7370340..d0a1c66 100644
--- a/chrome/browser/extensions/api/bookmarks/bookmarks_api.h
+++ b/chrome/browser/extensions/api/bookmarks/bookmarks_api.h
@@ -8,11 +8,11 @@
 #include <stdint.h>
 
 #include <list>
+#include <memory>
+#include <set>
 #include <string>
 #include <vector>
 
-#include "base/compiler_specific.h"
-#include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "components/bookmarks/browser/base_bookmark_model_observer.h"
 #include "components/bookmarks/browser/bookmark_node.h"
@@ -50,6 +50,8 @@
 class BookmarkEventRouter : public bookmarks::BookmarkModelObserver {
  public:
   explicit BookmarkEventRouter(Profile* profile);
+  BookmarkEventRouter(const BookmarkEventRouter&) = delete;
+  BookmarkEventRouter& operator=(const BookmarkEventRouter&) = delete;
   ~BookmarkEventRouter() override;
 
   // bookmarks::BookmarkModelObserver:
@@ -91,8 +93,6 @@
   content::BrowserContext* browser_context_;
   bookmarks::BookmarkModel* model_;
   bookmarks::ManagedBookmarkService* managed_;
-
-  DISALLOW_COPY_AND_ASSIGN(BookmarkEventRouter);
 };
 
 class BookmarksAPI : public BrowserContextKeyedAPI,
diff --git a/chrome/browser/extensions/api/bookmarks/bookmarks_api_unittest.cc b/chrome/browser/extensions/api/bookmarks/bookmarks_api_unittest.cc
index 384896d..1d59397 100644
--- a/chrome/browser/extensions/api/bookmarks/bookmarks_api_unittest.cc
+++ b/chrome/browser/extensions/api/bookmarks/bookmarks_api_unittest.cc
@@ -18,7 +18,9 @@
 
 class BookmarksApiUnittest : public ExtensionServiceTestBase {
  public:
-  BookmarksApiUnittest() {}
+  BookmarksApiUnittest() = default;
+  BookmarksApiUnittest(const BookmarksApiUnittest&) = delete;
+  BookmarksApiUnittest& operator=(const BookmarksApiUnittest&) = delete;
 
   void SetUp() override {
     ExtensionServiceTestBase::SetUp();
@@ -40,8 +42,6 @@
  private:
   bookmarks::BookmarkModel* model_ = nullptr;
   std::string node_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(BookmarksApiUnittest);
 };
 
 // Tests that running updating a bookmark folder's url does not succeed.
diff --git a/chrome/browser/extensions/api/braille_display_private/braille_controller.h b/chrome/browser/extensions/api/braille_display_private/braille_controller.h
index 5287209..c652731 100644
--- a/chrome/browser/extensions/api/braille_display_private/braille_controller.h
+++ b/chrome/browser/extensions/api/braille_display_private/braille_controller.h
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "base/callback_forward.h"
-#include "base/macros.h"
 #include "base/values.h"
 #include "chrome/common/extensions/api/braille_display_private.h"
 
@@ -23,6 +22,9 @@
  public:
   static BrailleController* GetInstance();
 
+  BrailleController(const BrailleController&) = delete;
+  BrailleController& operator=(const BrailleController&) = delete;
+
   virtual std::unique_ptr<DisplayState> GetDisplayState() = 0;
   virtual void WriteDots(const std::vector<uint8_t>& cells,
                          unsigned int cols,
@@ -31,11 +33,8 @@
   virtual void RemoveObserver(BrailleObserver* observer) = 0;
 
  protected:
-  BrailleController();
-  virtual ~BrailleController();
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BrailleController);
+  BrailleController() = default;
+  virtual ~BrailleController() = default;
 };
 
 // Observer for events from the BrailleController
diff --git a/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc b/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc
index c1a992125..e4a6ead 100644
--- a/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc
+++ b/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc
@@ -42,12 +42,6 @@
 
 }  // namespace
 
-BrailleController::BrailleController() {
-}
-
-BrailleController::~BrailleController() {
-}
-
 // static
 BrailleController* BrailleController::GetInstance() {
   return BrailleControllerImpl::GetInstance();
@@ -60,16 +54,13 @@
       base::LeakySingletonTraits<BrailleControllerImpl>>::get();
 }
 
-BrailleControllerImpl::BrailleControllerImpl()
-    : started_connecting_(false),
-      connect_scheduled_(false) {
+BrailleControllerImpl::BrailleControllerImpl() {
   create_brlapi_connection_function_ = base::Bind(
       &BrailleControllerImpl::CreateBrlapiConnection,
       base::Unretained(this));
 }
 
-BrailleControllerImpl::~BrailleControllerImpl() {
-}
+BrailleControllerImpl::~BrailleControllerImpl() = default;
 
 void BrailleControllerImpl::TryLoadLibBrlApi() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
diff --git a/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.h b/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.h
index db1054e1..ed61c60f2 100644
--- a/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.h
+++ b/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.h
@@ -6,10 +6,10 @@
 #define CHROME_BROWSER_EXTENSIONS_API_BRAILLE_DISPLAY_PRIVATE_BRAILLE_CONTROLLER_BRLAPI_H_
 
 #include <memory>
+#include <vector>
 
 #include "base/files/file_path.h"
 #include "base/files/file_path_watcher.h"
-#include "base/macros.h"
 #include "base/memory/singleton.h"
 #include "base/observer_list.h"
 #include "chrome/browser/extensions/api/braille_display_private/braille_controller.h"
@@ -24,6 +24,8 @@
 class BrailleControllerImpl : public BrailleController {
  public:
   static BrailleControllerImpl* GetInstance();
+  BrailleControllerImpl(const BrailleControllerImpl&) = delete;
+  BrailleControllerImpl& operator=(const BrailleControllerImpl&) = delete;
   std::unique_ptr<DisplayState> GetDisplayState() override;
   void WriteDots(const std::vector<uint8_t>& cells,
                  unsigned int cols,
@@ -72,8 +74,8 @@
   // Manipulated on the IO thread.
   LibBrlapiLoader libbrlapi_loader_;
   std::unique_ptr<BrlapiConnection> connection_;
-  bool started_connecting_;
-  bool connect_scheduled_;
+  bool started_connecting_ = false;
+  bool connect_scheduled_ = false;
   base::Time retry_connect_horizon_;
   scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
 
@@ -87,8 +89,6 @@
   bool skip_libbrlapi_so_load_ = false;
 
   friend struct base::DefaultSingletonTraits<BrailleControllerImpl>;
-
-  DISALLOW_COPY_AND_ASSIGN(BrailleControllerImpl);
 };
 
 }  // namespace braille_display_private
diff --git a/chrome/browser/extensions/api/braille_display_private/braille_controller_stub.cc b/chrome/browser/extensions/api/braille_display_private/braille_controller_stub.cc
index 46a76182..fb9a642e 100644
--- a/chrome/browser/extensions/api/braille_display_private/braille_controller_stub.cc
+++ b/chrome/browser/extensions/api/braille_display_private/braille_controller_stub.cc
@@ -4,22 +4,12 @@
 
 #include "chrome/browser/extensions/api/braille_display_private/braille_controller.h"
 
-#include <memory>
-
-#include "base/memory/singleton.h"
 #include "chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h"
-#include "chrome/common/extensions/api/braille_display_private.h"
 
 namespace extensions {
 namespace api {
 namespace braille_display_private {
 
-BrailleController::BrailleController() {
-}
-
-BrailleController::~BrailleController() {
-}
-
 // static
 BrailleController* BrailleController::GetInstance() {
   return StubBrailleController::GetInstance();
diff --git a/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc b/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
index 573132b..f486df4e 100644
--- a/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
+++ b/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
@@ -279,9 +279,11 @@
   class MockEventDelegate : public BrailleDisplayPrivateAPI::EventDelegate {
    public:
     MockEventDelegate() = default;
+    MockEventDelegate(const MockEventDelegate&) = delete;
+    MockEventDelegate& operator=(const MockEventDelegate&) = delete;
     ~MockEventDelegate() override = default;
 
-    int GetEventCount() { return event_count_; }
+    int GetEventCount() const { return event_count_; }
 
     // BrailleDisplayPrivateAPI::EventDelegate:
     void BroadcastEvent(std::unique_ptr<Event> event) override {
@@ -291,11 +293,13 @@
 
    private:
     int event_count_ = 0;
-
-    DISALLOW_COPY_AND_ASSIGN(MockEventDelegate);
   };
 
   BrailleDisplayPrivateAPIUserTest() = default;
+  BrailleDisplayPrivateAPIUserTest(const BrailleDisplayPrivateAPIUserTest&) =
+      delete;
+  BrailleDisplayPrivateAPIUserTest& operator=(
+      const BrailleDisplayPrivateAPIUserTest&) = delete;
   ~BrailleDisplayPrivateAPIUserTest() override = default;
 
   MockEventDelegate* SetMockEventDelegate(BrailleDisplayPrivateAPI* api) {
@@ -320,8 +324,6 @@
 
  protected:
   std::unique_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_;
-
-  DISALLOW_COPY_AND_ASSIGN(BrailleDisplayPrivateAPIUserTest);
 };
 
 IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateAPIUserTest, KeyEventOnLockScreen) {
diff --git a/chrome/browser/extensions/api/braille_display_private/brlapi_connection.cc b/chrome/browser/extensions/api/braille_display_private/brlapi_connection.cc
index 3d04c0cd..5f1ffb8 100644
--- a/chrome/browser/extensions/api/braille_display_private/brlapi_connection.cc
+++ b/chrome/browser/extensions/api/braille_display_private/brlapi_connection.cc
@@ -6,6 +6,8 @@
 
 #include <errno.h>
 
+#include <string>
+
 #include "base/files/file_descriptor_watcher_posix.h"
 #include "base/logging.h"
 #include "base/memory/free_deleter.h"
@@ -34,7 +36,8 @@
  public:
   explicit BrlapiConnectionImpl(LibBrlapiLoader* loader) :
       libbrlapi_loader_(loader) {}
-
+  BrlapiConnectionImpl(const BrlapiConnectionImpl&) = delete;
+  BrlapiConnectionImpl& operator=(const BrlapiConnectionImpl&) = delete;
   ~BrlapiConnectionImpl() override { Disconnect(); }
 
   ConnectResult Connect(const OnDataReadyCallback& on_data_ready) override;
@@ -54,16 +57,8 @@
   LibBrlapiLoader* libbrlapi_loader_;
   std::unique_ptr<brlapi_handle_t, base::FreeDeleter> handle_;
   std::unique_ptr<base::FileDescriptorWatcher::Controller> fd_controller_;
-
-  DISALLOW_COPY_AND_ASSIGN(BrlapiConnectionImpl);
 };
 
-BrlapiConnection::BrlapiConnection() {
-}
-
-BrlapiConnection::~BrlapiConnection() {
-}
-
 std::unique_ptr<BrlapiConnection> BrlapiConnection::Create(
     LibBrlapiLoader* loader) {
   DCHECK(loader->loaded());
@@ -73,9 +68,10 @@
 BrlapiConnection::ConnectResult BrlapiConnectionImpl::Connect(
     const OnDataReadyCallback& on_data_ready) {
   DCHECK(!handle_);
-  handle_.reset((brlapi_handle_t*) malloc(
-      libbrlapi_loader_->brlapi_getHandleSize()));
-  int fd = libbrlapi_loader_->brlapi__openConnection(handle_.get(), NULL, NULL);
+  handle_.reset(reinterpret_cast<brlapi_handle_t*>(
+      malloc(libbrlapi_loader_->brlapi_getHandleSize())));
+  int fd = libbrlapi_loader_->brlapi__openConnection(handle_.get(), nullptr,
+                                                     nullptr);
   if (fd < 0) {
     handle_.reset();
     VLOG(1) << "Error connecting to brlapi: " << BrlapiStrError();
@@ -87,10 +83,10 @@
   if (base::SysInfo::IsRunningOnChromeOS())
     path[pathElements++] = kDefaultTtyChromeOS;
 #endif
-  if (pathElements == 0 && getenv("WINDOWPATH") == NULL)
+  if (pathElements == 0 && getenv("WINDOWPATH") == nullptr)
     path[pathElements++] = kDefaultTtyLinux;
   if (libbrlapi_loader_->brlapi__enterTtyModeWithPath(
-          handle_.get(), path, pathElements, NULL) < 0) {
+          handle_.get(), path, pathElements, nullptr) < 0) {
     LOG(ERROR) << "brlapi: couldn't enter tty mode: " << BrlapiStrError();
     Disconnect();
     return CONNECT_ERROR_RETRY;
diff --git a/chrome/browser/extensions/api/braille_display_private/brlapi_connection.h b/chrome/browser/extensions/api/braille_display_private/brlapi_connection.h
index 3a7d028..030e3a9 100644
--- a/chrome/browser/extensions/api/braille_display_private/brlapi_connection.h
+++ b/chrome/browser/extensions/api/braille_display_private/brlapi_connection.h
@@ -11,7 +11,6 @@
 #include <vector>
 
 #include "base/callback_forward.h"
-#include "base/macros.h"
 #include "library_loaders/libbrlapi.h"
 
 namespace extensions {
@@ -32,7 +31,9 @@
 
   static std::unique_ptr<BrlapiConnection> Create(LibBrlapiLoader* loader);
 
-  virtual ~BrlapiConnection();
+  BrlapiConnection(const BrlapiConnection&) = delete;
+  BrlapiConnection& operator=(const BrlapiConnection&) = delete;
+  virtual ~BrlapiConnection() = default;
 
   virtual ConnectResult Connect(const OnDataReadyCallback& onDataReady) = 0;
 
@@ -71,8 +72,7 @@
   virtual bool GetCellSize(unsigned int* cell_size) = 0;
 
  protected:
-  BrlapiConnection();
-  DISALLOW_COPY_AND_ASSIGN(BrlapiConnection);
+  BrlapiConnection() = default;
 };
 
 }  // namespace braille_display_private
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
index e2b7e996..5c72eb1 100644
--- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
+++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
@@ -239,7 +239,7 @@
 
   content::RenderFrameHost* GetFrameByName(const std::string& name) const {
     return content::FrameMatchingPredicate(
-        web_contents(), base::Bind(&content::FrameMatchesName, name));
+        web_contents(), base::BindRepeating(&content::FrameMatchesName, name));
   }
 
   content::PageType GetPageType(Browser* browser) const {
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
index f69202e9..ce3fe53 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
@@ -91,18 +91,6 @@
   }
 
  protected:
-  void DidShowFullscreenWidget() override {
-    is_fullscreened_ = true;
-    if (capture_state_ == tab_capture::TAB_CAPTURE_STATE_ACTIVE)
-      registry_->DispatchStatusChangeEvent(this);
-  }
-
-  void DidDestroyFullscreenWidget() override {
-    is_fullscreened_ = false;
-    if (capture_state_ == tab_capture::TAB_CAPTURE_STATE_ACTIVE)
-      registry_->DispatchStatusChangeEvent(this);
-  }
-
   void DidToggleFullscreenModeForTab(bool entered_fullscreen,
                                      bool will_cause_resize) override {
     is_fullscreened_ = entered_fullscreen;
diff --git a/chrome/browser/extensions/chrome_app_api_browsertest.cc b/chrome/browser/extensions/chrome_app_api_browsertest.cc
index 7910e98..09fffe2 100644
--- a/chrome/browser/extensions/chrome_app_api_browsertest.cc
+++ b/chrome/browser/extensions/chrome_app_api_browsertest.cc
@@ -93,7 +93,7 @@
   content::RenderFrameHost* GetIFrame() {
     return content::FrameMatchingPredicate(
         browser()->tab_strip_model()->GetActiveWebContents(),
-        base::Bind(&content::FrameIsChildOfMainFrame));
+        base::BindRepeating(&content::FrameIsChildOfMainFrame));
   }
 };
 
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc
index 3b3ad2e..b191aae 100644
--- a/chrome/browser/extensions/extension_messages_apitest.cc
+++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -235,7 +235,7 @@
                                            const char* message = NULL) {
     content::RenderFrameHost* frame = content::FrameMatchingPredicate(
         browser()->tab_strip_model()->GetActiveWebContents(),
-        base::Bind(&content::FrameIsChildOfMainFrame));
+        base::BindRepeating(&content::FrameIsChildOfMainFrame));
     return CanConnectAndSendMessagesToFrame(frame, extension, message);
   }
 
@@ -260,7 +260,7 @@
   testing::AssertionResult AreAnyNonWebApisDefinedForIFrame() {
     content::RenderFrameHost* frame = content::FrameMatchingPredicate(
         browser()->tab_strip_model()->GetActiveWebContents(),
-        base::Bind(&content::FrameIsChildOfMainFrame));
+        base::BindRepeating(&content::FrameIsChildOfMainFrame));
     return AreAnyNonWebApisDefinedForFrame(frame);
   }
 
diff --git a/chrome/browser/extensions/extension_protocols_unittest.cc b/chrome/browser/extensions/extension_protocols_unittest.cc
index e56815b0..1f1fb67 100644
--- a/chrome/browser/extensions/extension_protocols_unittest.cc
+++ b/chrome/browser/extensions/extension_protocols_unittest.cc
@@ -319,7 +319,7 @@
           entries,
       ExtensionResourceAccessResult expected) {
     ASSERT_EQ(1u, entries.size());
-    EXPECT_EQ(test_ukm_id_, entries[0].source);
+    EXPECT_EQ(test_ukm_id_.ToInt64(), entries[0].source);
     ASSERT_EQ(1u, entries[0].metrics.size());
     EXPECT_EQ(blink::IdentifiableSurface::FromTypeAndToken(
                   blink::IdentifiableSurface::Type::kExtensionFileAccess,
diff --git a/chrome/browser/extensions/file_iframe_apitest.cc b/chrome/browser/extensions/file_iframe_apitest.cc
index 5ef4449f..046f91cc 100644
--- a/chrome/browser/extensions/file_iframe_apitest.cc
+++ b/chrome/browser/extensions/file_iframe_apitest.cc
@@ -46,7 +46,7 @@
     ASSERT_TRUE(background_host);
     content::RenderFrameHost* file_iframe = content::FrameMatchingPredicate(
         background_host->host_contents(),
-        base::Bind(&content::FrameMatchesName, "file_iframe"));
+        base::BindRepeating(&content::FrameMatchesName, "file_iframe"));
     bool is_file_url = file_iframe->GetLastCommittedURL() == GURL("file:///");
     EXPECT_EQ(expect_will_load_file_iframe, is_file_url)
         << "Unexpected committed url: "
diff --git a/chrome/browser/extensions/subscribe_page_action_browsertest.cc b/chrome/browser/extensions/subscribe_page_action_browsertest.cc
index 16dc424c..604604e5 100644
--- a/chrome/browser/extensions/subscribe_page_action_browsertest.cc
+++ b/chrome/browser/extensions/subscribe_page_action_browsertest.cc
@@ -161,7 +161,7 @@
   EXPECT_STREQ(expected_msg.c_str(), message.c_str());
 
   content::RenderFrameHost* frame = content::FrameMatchingPredicate(
-      tab, base::Bind(&content::FrameMatchesName, "preview"));
+      tab, base::BindRepeating(&content::FrameMatchesName, "preview"));
   ASSERT_TRUE(ValidatePageElement(
       tab->GetMainFrame(), kScriptFeedTitle, expected_feed_title));
   ASSERT_TRUE(ValidatePageElement(frame, kScriptAnchor, expected_item_title));
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 64fbfbc..0af5697 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2189,11 +2189,6 @@
     "expiry_milestone": 90
   },
   {
-    "name": "enable-tab-search-fixed-entrypoint",
-    "owners": [ "tluk@google.com", "robliao@google.com" ],
-    "expiry_milestone": 90
-  },
-  {
     "name": "enable-tab-switcher-on-return",
     "owners": [ "memex-team@google.com" ],
     "expiry_milestone": 90
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 79be1ff0..8e7c9e5c 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -974,12 +974,6 @@
 const char kEnableTabSearchDescription[] =
     "Enable the Tab Search feature in Top Chrome UI, which will show a popup "
     "bubble that allows users to search over their currently open tabs.";
-const char kEnableTabSearchFixedEntrypointName[] =
-    "Enable Tab Search fixed "
-    "entrypoint";
-const char kEnableTabSearchFixedEntrypointDescription[] =
-    "Enable the Tab "
-    "Search feature in Top Chrome UI having a fixed button position.";
 #endif  // BUILDFLAG(ENABLE_TAB_SEARCH)";
 
 const char kEnableTextFragmentAnchorName[] = "Enable Text Fragment Anchor.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 3d820a28..39cd8902 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -565,8 +565,6 @@
 #if BUILDFLAG(ENABLE_TAB_SEARCH)
 extern const char kEnableTabSearchName[];
 extern const char kEnableTabSearchDescription[];
-extern const char kEnableTabSearchFixedEntrypointName[];
-extern const char kEnableTabSearchFixedEntrypointDescription[];
 #endif  // BUILDFLAG(ENABLE_TAB_SEARCH)
 
 extern const char kEnableTextFragmentAnchorName[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 75e5e4e..d0ae84f 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -13,7 +13,6 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/stl_util.h"
 #include "chrome/browser/flags/jni_headers/ChromeFeatureList_jni.h"
-#include "chrome/browser/notifications/chime/android/features.h"
 #include "chrome/browser/performance_hints/performance_hints_features.h"
 #include "chrome/browser/share/features.h"
 #include "chrome/browser/sharing/shared_clipboard/feature_flags.h"
@@ -229,7 +228,6 @@
     &language::kExplicitLanguageAsk,
     &language::kTranslateIntent,
     &messages::kMessagesForAndroidInfrastructure,
-    &notifications::features::kUseChimeAndroidSdk,
     &offline_pages::kOfflineIndicatorFeature,
     &offline_pages::kOfflineIndicatorAlwaysHttpProbeFeature,
     &offline_pages::kOfflinePagesCTFeature,    // See crbug.com/620421.
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
index bce2bf9..0ae21da 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
@@ -79,7 +79,6 @@
             put(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP, false);
             put(ChromeFeatureList.MESSAGES_FOR_ANDROID_INFRASTRUCTURE, false);
             put(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR, false);
-            put(ChromeFeatureList.USE_CHIME_ANDROID_SDK, false);
         }
     };
 
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index a3606e8..1f40bdd 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -438,7 +438,6 @@
     public static final String UPDATE_NOTIFICATION_IMMEDIATE_SHOW_OPTION =
             "UpdateNotificationScheduleServiceImmediateShowOption";
     public static final String USAGE_STATS = "UsageStats";
-    public static final String USE_CHIME_ANDROID_SDK = "UseChimeAndroidSdk";
     public static final String VR_BROWSING_FEEDBACK = "VrBrowsingFeedback";
     public static final String WEBAPK_ADAPTIVE_ICON = "WebApkAdaptiveIcon";
     public static final String WEB_AUTH = "WebAuthentication";
diff --git a/chrome/browser/history/chrome_history_client.cc b/chrome/browser/history/chrome_history_client.cc
index 48b4f54..4ffc0ff1 100644
--- a/chrome/browser/history/chrome_history_client.cc
+++ b/chrome/browser/history/chrome_history_client.cc
@@ -30,12 +30,12 @@
     history::HistoryService* history_service) {
   if (bookmark_model_) {
     on_bookmarks_removed_ =
-        base::Bind(&history::HistoryService::URLsNoLongerBookmarked,
-                   base::Unretained(history_service));
+        base::BindRepeating(&history::HistoryService::URLsNoLongerBookmarked,
+                            base::Unretained(history_service));
     favicons_changed_subscription_ =
         history_service->AddFaviconsChangedCallback(
-            base::Bind(&bookmarks::BookmarkModel::OnFaviconsChanged,
-                       base::Unretained(bookmark_model_)));
+            base::BindRepeating(&bookmarks::BookmarkModel::OnFaviconsChanged,
+                                base::Unretained(bookmark_model_)));
   }
 }
 
diff --git a/chrome/browser/history/chrome_history_client.h b/chrome/browser/history/chrome_history_client.h
index 35ad6cf..0c8b0cce 100644
--- a/chrome/browser/history/chrome_history_client.h
+++ b/chrome/browser/history/chrome_history_client.h
@@ -58,7 +58,7 @@
   bookmarks::BookmarkModel* bookmark_model_;
 
   // Callback invoked when URLs are removed from BookmarkModel.
-  base::Callback<void(const std::set<GURL>&)> on_bookmarks_removed_;
+  base::RepeatingCallback<void(const std::set<GURL>&)> on_bookmarks_removed_;
 
   // Subscription for notifications of changes to favicons.
   std::unique_ptr<
diff --git a/chrome/browser/history/top_sites_factory.cc b/chrome/browser/history/top_sites_factory.cc
index f9b6a19..1cae360 100644
--- a/chrome/browser/history/top_sites_factory.cc
+++ b/chrome/browser/history/top_sites_factory.cc
@@ -112,7 +112,7 @@
                                            ServiceAccessType::EXPLICIT_ACCESS);
   scoped_refptr<history::TopSitesImpl> top_sites(new history::TopSitesImpl(
       profile->GetPrefs(), history_service, prepopulated_page_list,
-      base::Bind(CanAddURLToHistory)));
+      base::BindRepeating(CanAddURLToHistory)));
   top_sites->Init(context->GetPath().Append(history::kTopSitesFilename));
   return top_sites;
 }
diff --git a/chrome/browser/media/offscreen_tab.cc b/chrome/browser/media/offscreen_tab.cc
index 3455173d..aba8e22 100644
--- a/chrome/browser/media/offscreen_tab.cc
+++ b/chrome/browser/media/offscreen_tab.cc
@@ -290,11 +290,6 @@
   return true;
 }
 
-bool OffscreenTab::EmbedsFullscreenWidget() {
-  // OffscreenTab will manage fullscreen widgets.
-  return true;
-}
-
 void OffscreenTab::EnterFullscreenModeForTab(
     content::RenderFrameHost* requesting_frame,
     const blink::mojom::FullscreenOptions& options) {
@@ -350,16 +345,6 @@
          type == blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE;
 }
 
-void OffscreenTab::DidShowFullscreenWidget() {
-  if (!offscreen_tab_web_contents_->IsBeingCaptured() ||
-      offscreen_tab_web_contents_->GetPreferredSize().IsEmpty())
-    return;  // Do nothing, since no preferred size is specified.
-  content::RenderWidgetHostView* const current_fs_view =
-      offscreen_tab_web_contents_->GetFullscreenRenderWidgetHostView();
-  if (current_fs_view)
-    current_fs_view->SetSize(offscreen_tab_web_contents_->GetPreferredSize());
-}
-
 void OffscreenTab::DidStartNavigation(
     content::NavigationHandle* navigation_handle) {
   DCHECK(offscreen_tab_web_contents_.get());
diff --git a/chrome/browser/media/offscreen_tab.h b/chrome/browser/media/offscreen_tab.h
index 361d4d7e..fb09bf2c 100644
--- a/chrome/browser/media/offscreen_tab.h
+++ b/chrome/browser/media/offscreen_tab.h
@@ -108,7 +108,6 @@
       const GURL& opener_url,
       const std::string& frame_name,
       const GURL& target_url) final;
-  bool EmbedsFullscreenWidget() final;
   void EnterFullscreenModeForTab(
       content::RenderFrameHost* requesting_frame,
       const blink::mojom::FullscreenOptions& options) final;
@@ -125,7 +124,6 @@
                                   blink::mojom::MediaStreamType type) final;
 
   // content::WebContentsObserver overrides
-  void DidShowFullscreenWidget() final;
   void DidStartNavigation(content::NavigationHandle* navigation_handle) final;
 
   bool in_fullscreen_mode() const { return !non_fullscreen_size_.IsEmpty(); }
diff --git a/chrome/browser/media/webrtc/tab_desktop_media_list_unittest.cc b/chrome/browser/media/webrtc/tab_desktop_media_list_unittest.cc
index dd979119..e463955 100644
--- a/chrome/browser/media/webrtc/tab_desktop_media_list_unittest.cc
+++ b/chrome/browser/media/webrtc/tab_desktop_media_list_unittest.cc
@@ -166,7 +166,7 @@
 
     // Create browser.
     Browser::CreateParams profile_params(profile_, true);
-    browser_ = CreateBrowserWithTestWindowForParams(&profile_params);
+    browser_ = CreateBrowserWithTestWindowForParams(profile_params);
     ASSERT_TRUE(browser_);
     for (int i = 0; i < kDefaultSourceCount; i++) {
       AddWebcontents(i + 1);
diff --git a/chrome/browser/memory/memory_kills_monitor.cc b/chrome/browser/memory/memory_kills_monitor.cc
index cc9ba5d..b66e97d1 100644
--- a/chrome/browser/memory/memory_kills_monitor.cc
+++ b/chrome/browser/memory/memory_kills_monitor.cc
@@ -15,6 +15,7 @@
 #include "base/strings/string_split.h"
 #include "base/synchronization/atomic_flag.h"
 #include "chrome/browser/memory/memory_kills_histogram.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace memory {
@@ -47,14 +48,20 @@
 }
 
 // static
-void MemoryKillsMonitor::LogLowMemoryKill(
-    const std::string& type, int estimated_freed_kb) {
+void MemoryKillsMonitor::LogLowMemoryKill(const std::string& type,
+                                          int estimated_freed_kb) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   g_memory_kills_monitor_instance.Get().LogLowMemoryKillImpl(
       type, estimated_freed_kb);
 }
 
+// static
+void MemoryKillsMonitor::LogArcOOMKill(unsigned long current_oom_kills) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  g_memory_kills_monitor_instance.Get().LogArcOOMKillImpl(current_oom_kills);
+}
+
 void MemoryKillsMonitor::LoggedInStateChanged() {
   VLOG(2) << "LoggedInStateChanged";
   auto* login_state = chromeos::LoginState::Get();
@@ -107,13 +114,13 @@
 void MemoryKillsMonitor::CheckOOMKillImpl(unsigned long current_oom_kills) {
   DCHECK(monitoring_started_.IsSet());
 
-  unsigned long oom_kills_increased = current_oom_kills - last_oom_kills_count_;
-  if (oom_kills_increased == 0)
+  unsigned long oom_kills_delta = current_oom_kills - last_oom_kills_count_;
+  if (oom_kills_delta == 0)
     return;
 
-  VLOG(1) << "OOM_KILLS " << oom_kills_increased << " times";
+  VLOG(1) << "OOM_KILLS " << oom_kills_delta << " times";
 
-  for (int i = 0; i < oom_kills_increased; ++i) {
+  for (int i = 0; i < oom_kills_delta; ++i) {
     ++oom_kills_count_;
 
     // Report the cumulative count of killed process in one login session. For
@@ -152,6 +159,22 @@
   UMA_HISTOGRAM_MEMORY_KB("Arc.LowMemoryKiller.FreedSize", estimated_freed_kb);
 }
 
+void MemoryKillsMonitor::LogArcOOMKillImpl(unsigned long current_oom_kills) {
+  DCHECK(monitoring_started_.IsSet());
+  unsigned long oom_kills_delta = current_oom_kills - last_arc_oom_kills_count_;
+  if (oom_kills_delta == 0)
+    return;
+
+  VLOG(1) << "ARC_OOM_KILLS " << oom_kills_delta << " times";
+
+  for (int i = 0; i < oom_kills_delta; ++i) {
+    ++oom_kills_count_;
+    // Report cumulative count of killed processes in one login session.
+    UMA_HISTOGRAM_CUSTOM_COUNTS("Arc.OOMKills.Count", oom_kills_count_, 1, 1000,
+                                1001);
+  }
+  last_arc_oom_kills_count_ = current_oom_kills;
+}
 MemoryKillsMonitor* MemoryKillsMonitor::GetForTesting() {
   return g_memory_kills_monitor_instance.Pointer();
 }
diff --git a/chrome/browser/memory/memory_kills_monitor.h b/chrome/browser/memory/memory_kills_monitor.h
index ac86142d..58b4245b 100644
--- a/chrome/browser/memory/memory_kills_monitor.h
+++ b/chrome/browser/memory/memory_kills_monitor.h
@@ -39,6 +39,9 @@
   // after StartMonitoring() has been called.
   static void LogLowMemoryKill(const std::string& type, int estimated_freed_kb);
 
+  // A convenient function to log ARCVM OOM kills.
+  static void LogArcOOMKill(unsigned long current_oom_kills);
+
  private:
   FRIEND_TEST_ALL_PREFIXES(MemoryKillsMonitorTest, TestHistograms);
 
@@ -60,6 +63,9 @@
   // Split CheckOOMKill and CheckOOMKillImpl for testing.
   void CheckOOMKillImpl(unsigned long current_oom_kills);
 
+  // Logs ARCVM OOM kill.
+  void LogArcOOMKillImpl(unsigned long current_oom_kills);
+
   // A flag set when StartMonitoring() is called to indicate that monitoring has
   // been started.
   base::AtomicFlag monitoring_started_;
@@ -76,6 +82,9 @@
   // The last oom kills count from |GetCurrentOOMKills|.
   unsigned long last_oom_kills_count_ = 0;
 
+  // The last ARCVM OOM kills count.
+  unsigned long last_arc_oom_kills_count_ = 0;
+
   base::RepeatingTimer checking_timer_;
 
   DISALLOW_COPY_AND_ASSIGN(MemoryKillsMonitor);
diff --git a/chrome/browser/metrics/desktop_session_duration/touch_mode_stats_tracker_unittest.cc b/chrome/browser/metrics/desktop_session_duration/touch_mode_stats_tracker_unittest.cc
index f0f5391..d9ec4198 100644
--- a/chrome/browser/metrics/desktop_session_duration/touch_mode_stats_tracker_unittest.cc
+++ b/chrome/browser/metrics/desktop_session_duration/touch_mode_stats_tracker_unittest.cc
@@ -79,7 +79,7 @@
         ui::TouchUiController::Get());
 
     Browser::CreateParams params(profile_, false);
-    browser_ = CreateBrowserWithTestWindowForParams(&params);
+    browser_ = CreateBrowserWithTestWindowForParams(params);
   }
 
   void TearDown() override {
diff --git a/chrome/browser/notifications/chime/android/BUILD.gn b/chrome/browser/notifications/chime/android/BUILD.gn
index a32585af..4e47c14 100644
--- a/chrome/browser/notifications/chime/android/BUILD.gn
+++ b/chrome/browser/notifications/chime/android/BUILD.gn
@@ -13,7 +13,6 @@
     "//base:base_java",
     "//base:jni_java",
     "//chrome/android/modules/chime/public:java",
-    "//chrome/browser/flags:java",
   ]
 }
 
@@ -23,5 +22,14 @@
     "features.h",
   ]
 
-  deps = [ "//base" ]
+  deps = [
+    ":jni_headers",
+    "//base",
+  ]
+}
+
+generate_jni("jni_headers") {
+  visibility = [ ":*" ]
+
+  sources = [ "java/src/org/chromium/chrome/browser/notifications/chime/ChimeSession.java" ]
 }
diff --git a/chrome/browser/notifications/chime/android/features.cc b/chrome/browser/notifications/chime/android/features.cc
index afb0c10..91a0e86 100644
--- a/chrome/browser/notifications/chime/android/features.cc
+++ b/chrome/browser/notifications/chime/android/features.cc
@@ -3,6 +3,12 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/notifications/chime/android/features.h"
+#include "chrome/browser/notifications/chime/android/jni_headers/ChimeSession_jni.h"
+
+jboolean JNI_ChimeSession_IsEnabled(JNIEnv* env) {
+  return base::FeatureList::IsEnabled(
+      notifications::features::kUseChimeAndroidSdk);
+}
 
 namespace notifications {
 namespace features {
diff --git a/chrome/browser/notifications/chime/android/java/src/org/chromium/chrome/browser/notifications/chime/ChimeSession.java b/chrome/browser/notifications/chime/android/java/src/org/chromium/chrome/browser/notifications/chime/ChimeSession.java
index 8243a695..87bb5418 100644
--- a/chrome/browser/notifications/chime/android/java/src/org/chromium/chrome/browser/notifications/chime/ChimeSession.java
+++ b/chrome/browser/notifications/chime/android/java/src/org/chromium/chrome/browser/notifications/chime/ChimeSession.java
@@ -4,8 +4,7 @@
 
 package org.chromium.chrome.browser.notifications.chime;
 
-import org.chromium.chrome.browser.flags.CachedFeatureFlags;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.modules.chime.ChimeModule;
 
 /**
@@ -15,23 +14,12 @@
     private static boolean sRegistered;
 
     /**
-     * Initializes the Chime component. If the DFM is not installed or the feature flag is not
-     * enabled, do nothing.
+     * Registers to Chime and start to receive notifications.
      */
-    public static void init() {
-        // Don't init if we don't install DFM yet or the feature is not enabled. The DFM install
-        // happens during the first time registration.
-        if (!ChimeModule.isInstalled() || !isEnabled()) return;
-
-        ChimeModule.getImpl().initialize();
-    }
-
-    /**
-     * Registers to Chime and start to receive notifications. Internally it will install the DFM
-     * first.
-     */
-    public static void register() {
-        if (!isEnabled() || sRegistered) return;
+    public static void start() {
+        // TODO(xingliu): Find a better way to access feature in Java code.
+        // https://crbug.com/1017860.
+        if (!ChimeSessionJni.get().isEnabled() || sRegistered) return;
 
         // Install the DFM and then reigster.
         if (ChimeModule.isInstalled()) {
@@ -50,7 +38,11 @@
         ChimeModule.getImpl().register();
     }
 
-    private static boolean isEnabled() {
-        return CachedFeatureFlags.isEnabled(ChromeFeatureList.USE_CHIME_ANDROID_SDK);
+    @NativeMethods
+    interface Natives {
+        /**
+         * @return Whether Chime is enabled.
+         */
+        boolean isEnabled();
     }
 }
diff --git a/chrome/browser/paint_preview/services/paint_preview_tab_service.cc b/chrome/browser/paint_preview/services/paint_preview_tab_service.cc
index e4b4bc8..442c1282 100644
--- a/chrome/browser/paint_preview/services/paint_preview_tab_service.cc
+++ b/chrome/browser/paint_preview/services/paint_preview_tab_service.cc
@@ -14,6 +14,7 @@
 #include "base/task/task_traits.h"
 #include "components/paint_preview/browser/file_manager.h"
 #include "components/paint_preview/browser/warm_compositor.h"
+#include "content/public/browser/render_process_host.h"
 #include "ui/gfx/geometry/rect.h"
 
 #if defined(OS_ANDROID)
@@ -109,6 +110,7 @@
       base::BindOnce(&PaintPreviewTabService::CaptureTabInternal,
                      weak_ptr_factory_.GetWeakPtr(), tab_id, key,
                      contents->GetMainFrame()->GetFrameTreeNodeId(),
+                     contents->GetMainFrame()->GetGlobalFrameRoutingId(),
                      std::move(callback)));
 }
 
@@ -228,6 +230,7 @@
     int tab_id,
     const DirectoryKey& key,
     int frame_tree_node_id,
+    content::GlobalFrameRoutingId frame_routing_id,
     FinishedCallback callback,
     const base::Optional<base::FilePath>& file_path) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -237,7 +240,9 @@
   }
   auto* contents =
       content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
-  if (!contents) {
+  auto* rfh = content::RenderFrameHost::FromID(frame_routing_id);
+  if (!contents || !rfh || contents->IsBeingDestroyed() ||
+      contents->GetMainFrame() != rfh || !rfh->IsCurrent()) {
     std::move(callback).Run(Status::kWebContentsGone);
     return;
   }
diff --git a/chrome/browser/paint_preview/services/paint_preview_tab_service.h b/chrome/browser/paint_preview/services/paint_preview_tab_service.h
index 0a591c7..4aa0b27 100644
--- a/chrome/browser/paint_preview/services/paint_preview_tab_service.h
+++ b/chrome/browser/paint_preview/services/paint_preview_tab_service.h
@@ -113,6 +113,7 @@
   void CaptureTabInternal(int tab_id,
                           const DirectoryKey& key,
                           int frame_tree_node_id,
+                          content::GlobalFrameRoutingId frame_routing_id,
                           FinishedCallback callback,
                           const base::Optional<base::FilePath>& file_path);
 
diff --git a/chrome/browser/paint_preview/services/paint_preview_tab_service_unittest.cc b/chrome/browser/paint_preview/services/paint_preview_tab_service_unittest.cc
index 86d91bf8a..899c383 100644
--- a/chrome/browser/paint_preview/services/paint_preview_tab_service_unittest.cc
+++ b/chrome/browser/paint_preview/services/paint_preview_tab_service_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/test/task_environment.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/paint_preview/common/mojom/paint_preview_recorder.mojom.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_utils.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
@@ -83,6 +84,9 @@
  protected:
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
+    NavigateAndCommit(GURL("https://www.example.com/"),
+                      ui::PageTransition::PAGE_TRANSITION_FIRST);
+    task_environment()->RunUntilIdle();
     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
     service_ = std::make_unique<PaintPreviewTabService>(
         temp_dir_.GetPath(), kFeatureName, nullptr, false);
@@ -90,6 +94,8 @@
     EXPECT_TRUE(service_->CacheInitialized());
   }
 
+  void TearDown() override { ChromeRenderViewHostTestHarness::TearDown(); }
+
   PaintPreviewTabService* GetService() { return service_.get(); }
 
   void OverrideInterface(MockPaintPreviewRecorder* recorder) {
@@ -128,8 +134,6 @@
 };
 
 TEST_F(PaintPreviewTabServiceTest, CaptureTab) {
-  content::NavigationSimulator::NavigateAndCommitFromBrowser(
-      web_contents(), GURL("http://www.example.com"));
   const int kTabId = 1U;
 
   MockPaintPreviewRecorder recorder;
@@ -163,8 +167,6 @@
 }
 
 TEST_F(PaintPreviewTabServiceTest, CaptureTabFailed) {
-  content::NavigationSimulator::NavigateAndCommitFromBrowser(
-      web_contents(), GURL("http://www.example.com"));
   const int kTabId = 1U;
 
   MockPaintPreviewRecorder recorder;
@@ -199,8 +201,6 @@
 }
 
 TEST_F(PaintPreviewTabServiceTest, CaptureTabTwice) {
-  content::NavigationSimulator::NavigateAndCommitFromBrowser(
-      web_contents(), GURL("http://www.example.com"));
   const int kTabId = 1U;
 
   MockPaintPreviewRecorder recorder;
@@ -387,8 +387,6 @@
 }
 
 TEST_F(PaintPreviewTabServiceTest, EarlyCapture) {
-  content::NavigationSimulator::NavigateAndCommitFromBrowser(
-      web_contents(), GURL("http://www.example.com"));
   const int kTabId = 1U;
 
   MockPaintPreviewRecorder recorder;
@@ -423,8 +421,6 @@
 }
 
 TEST_F(PaintPreviewTabServiceTest, CaptureTabAndCleanup) {
-  content::NavigationSimulator::NavigateAndCommitFromBrowser(
-      web_contents(), GURL("http://www.example.com"));
   const int kTabId = 1U;
 
   MockPaintPreviewRecorder recorder;
diff --git a/chrome/browser/prerender/isolated/OWNERS b/chrome/browser/prerender/isolated/OWNERS
new file mode 100644
index 0000000..12f637f
--- /dev/null
+++ b/chrome/browser/prerender/isolated/OWNERS
@@ -0,0 +1 @@
+robertogden@chromium.org
diff --git a/chrome/browser/privacy_budget/privacy_budget_browsertest.cc b/chrome/browser/privacy_budget/privacy_budget_browsertest.cc
index df1362f6..d73fdda 100644
--- a/chrome/browser/privacy_budget/privacy_budget_browsertest.cc
+++ b/chrome/browser/privacy_budget/privacy_budget_browsertest.cc
@@ -13,6 +13,7 @@
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
 #include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
@@ -26,6 +27,15 @@
 
 namespace {
 
+using testing::IsSupersetOf;
+using testing::Key;
+
+uint64_t HashFeature(const blink::mojom::WebFeature& feature) {
+  return blink::IdentifiableSurface::FromTypeAndToken(
+             blink::IdentifiableSurface::Type::kWebFeature, feature)
+      .ToUkmMetricHash();
+}
+
 // This test runs on Android as well as desktop platforms.
 class PrivacyBudgetBrowserTest : public PlatformBrowserTest {
  public:
@@ -91,22 +101,23 @@
   // Shouldn't be more than one source here. If this changes, then we'd need to
   // adjust this test to deal.
   ASSERT_EQ(1u, merged_entries.size());
-  const auto& metrics = merged_entries.begin()->second->metrics;
 
   // All of the following features should be included in the list of returned
   // metrics here. The exact values depend on the test host.
-  for (auto feature :
-       {blink::mojom::WebFeature::kV8Screen_Height_AttributeGetter,
-        blink::mojom::WebFeature::kV8Screen_Width_AttributeGetter,
-        blink::mojom::WebFeature::kV8Screen_AvailLeft_AttributeGetter,
-        blink::mojom::WebFeature::kV8Screen_AvailTop_AttributeGetter,
-        blink::mojom::WebFeature::kV8Screen_AvailWidth_AttributeGetter,
-        blink::mojom::WebFeature::kV8Screen_Height_AttributeGetter}) {
-    EXPECT_TRUE(metrics.contains(
-        blink::IdentifiableSurface::FromTypeAndToken(
-            blink::IdentifiableSurface::Type::kWebFeature, feature)
-            .ToUkmMetricHash()));
-  }
+  EXPECT_THAT(
+      merged_entries.begin()->second->metrics,
+      IsSupersetOf({
+          Key(HashFeature(
+              blink::mojom::WebFeature::kV8Screen_Height_AttributeGetter)),
+          Key(HashFeature(
+              blink::mojom::WebFeature::kV8Screen_Width_AttributeGetter)),
+          Key(HashFeature(
+              blink::mojom::WebFeature::kV8Screen_AvailLeft_AttributeGetter)),
+          Key(HashFeature(
+              blink::mojom::WebFeature::kV8Screen_AvailTop_AttributeGetter)),
+          Key(HashFeature(
+              blink::mojom::WebFeature::kV8Screen_AvailWidth_AttributeGetter)),
+      }));
 }
 
 #if BUILDFLAG(FIELDTRIAL_TESTING_ENABLED)
diff --git a/chrome/browser/profiles/profile_activity_metrics_recorder_unittest.cc b/chrome/browser/profiles/profile_activity_metrics_recorder_unittest.cc
index 9b283a7..51e7a690 100644
--- a/chrome/browser/profiles/profile_activity_metrics_recorder_unittest.cc
+++ b/chrome/browser/profiles/profile_activity_metrics_recorder_unittest.cc
@@ -57,7 +57,7 @@
 
   void ActivateBrowser(Profile* profile) {
     Browser::CreateParams browser_params(profile, false);
-    browsers_.push_back(CreateBrowserWithTestWindowForParams(&browser_params));
+    browsers_.push_back(CreateBrowserWithTestWindowForParams(browser_params));
 
     // This triggers the recorder to post a task, wait until that's done.
     BrowserList::SetLastActive(browsers_.back().get());
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
index 3e437d673..07b904c 100644
--- a/chrome/browser/profiles/profile_manager_unittest.cc
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -920,7 +920,7 @@
   // Create a browser for profile1.
   Browser::CreateParams profile1_params(profile1, true);
   std::unique_ptr<Browser> browser1a(
-      CreateBrowserWithTestWindowForParams(&profile1_params));
+      CreateBrowserWithTestWindowForParams(profile1_params));
 
   last_opened_profiles = profile_manager->GetLastOpenedProfiles();
   ASSERT_EQ(1U, last_opened_profiles.size());
@@ -929,7 +929,7 @@
   // And for profile2.
   Browser::CreateParams profile2_params(profile2, true);
   std::unique_ptr<Browser> browser2(
-      CreateBrowserWithTestWindowForParams(&profile2_params));
+      CreateBrowserWithTestWindowForParams(profile2_params));
 
   last_opened_profiles = profile_manager->GetLastOpenedProfiles();
   ASSERT_EQ(2U, last_opened_profiles.size());
@@ -938,7 +938,7 @@
 
   // Adding more browsers doesn't change anything.
   std::unique_ptr<Browser> browser1b(
-      CreateBrowserWithTestWindowForParams(&profile1_params));
+      CreateBrowserWithTestWindowForParams(profile1_params));
   last_opened_profiles = profile_manager->GetLastOpenedProfiles();
   ASSERT_EQ(2U, last_opened_profiles.size());
   EXPECT_EQ(profile1, last_opened_profiles[0]);
@@ -982,12 +982,12 @@
   // Create a browser for profile1.
   Browser::CreateParams profile1_params(profile1, true);
   std::unique_ptr<Browser> browser1(
-      CreateBrowserWithTestWindowForParams(&profile1_params));
+      CreateBrowserWithTestWindowForParams(profile1_params));
 
   // And for profile2.
   Browser::CreateParams profile2_params(profile2, true);
   std::unique_ptr<Browser> browser2(
-      CreateBrowserWithTestWindowForParams(&profile2_params));
+      CreateBrowserWithTestWindowForParams(profile2_params));
 
   std::vector<Profile*> last_opened_profiles =
       profile_manager->GetLastOpenedProfiles();
@@ -1032,7 +1032,7 @@
   // Create a browser for profile1.
   Browser::CreateParams profile1_params(profile1, true);
   std::unique_ptr<Browser> browser1(
-      CreateBrowserWithTestWindowForParams(&profile1_params));
+      CreateBrowserWithTestWindowForParams(profile1_params));
 
   last_opened_profiles = profile_manager->GetLastOpenedProfiles();
   ASSERT_EQ(1U, last_opened_profiles.size());
@@ -1041,7 +1041,7 @@
   // And for profile2.
   Browser::CreateParams profile2_params(profile1->GetPrimaryOTRProfile(), true);
   std::unique_ptr<Browser> browser2a(
-      CreateBrowserWithTestWindowForParams(&profile2_params));
+      CreateBrowserWithTestWindowForParams(profile2_params));
 
   last_opened_profiles = profile_manager->GetLastOpenedProfiles();
   ASSERT_EQ(1U, last_opened_profiles.size());
@@ -1049,7 +1049,7 @@
 
   // Adding more browsers doesn't change anything.
   std::unique_ptr<Browser> browser2b(
-      CreateBrowserWithTestWindowForParams(&profile2_params));
+      CreateBrowserWithTestWindowForParams(profile2_params));
   last_opened_profiles = profile_manager->GetLastOpenedProfiles();
   ASSERT_EQ(1U, last_opened_profiles.size());
   EXPECT_EQ(profile1, last_opened_profiles[0]);
@@ -1091,7 +1091,7 @@
   // Create a browser for the profile.
   Browser::CreateParams profile_params(profile, true);
   std::unique_ptr<Browser> browser(
-      CreateBrowserWithTestWindowForParams(&profile_params));
+      CreateBrowserWithTestWindowForParams(profile_params));
   last_used_profile = profile_manager->GetLastUsedProfile();
   EXPECT_NE(profile, last_used_profile);
 
@@ -1132,16 +1132,16 @@
   // Create a browser for profile1.
   Browser::CreateParams profile1_params(normal_profile, true);
   std::unique_ptr<Browser> browser1(
-      CreateBrowserWithTestWindowForParams(&profile1_params));
+      CreateBrowserWithTestWindowForParams(profile1_params));
 
   // Create browsers for the ephemeral profile.
   Browser::CreateParams profile2_params(ephemeral_profile1, true);
   std::unique_ptr<Browser> browser2(
-      CreateBrowserWithTestWindowForParams(&profile2_params));
+      CreateBrowserWithTestWindowForParams(profile2_params));
 
   Browser::CreateParams profile3_params(ephemeral_profile2, true);
   std::unique_ptr<Browser> browser3(
-      CreateBrowserWithTestWindowForParams(&profile3_params));
+      CreateBrowserWithTestWindowForParams(profile3_params));
 
   std::vector<Profile*> last_opened_profiles =
       profile_manager->GetLastOpenedProfiles();
diff --git a/chrome/browser/resource_coordinator/tab_activity_watcher_unittest.cc b/chrome/browser/resource_coordinator/tab_activity_watcher_unittest.cc
index 89063e4..834bf1f 100644
--- a/chrome/browser/resource_coordinator/tab_activity_watcher_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_activity_watcher_unittest.cc
@@ -123,7 +123,7 @@
   SetParams({{"scorer_type", "0"}});
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
-      CreateBrowserWithTestWindowForParams(&params);
+      CreateBrowserWithTestWindowForParams(params);
   TabStripModel* tab_strip_model = browser->tab_strip_model();
 
   // Create lifecycleunits.
@@ -149,7 +149,7 @@
   SetParams({{"scorer_type", "3"}});
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
-      CreateBrowserWithTestWindowForParams(&params);
+      CreateBrowserWithTestWindowForParams(params);
   TabStripModel* tab_strip_model = browser->tab_strip_model();
 
   // Create lifecycleunits.
@@ -184,7 +184,7 @@
   SetParams({{"scorer_type", "3"}});
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
-      CreateBrowserWithTestWindowForParams(&params);
+      CreateBrowserWithTestWindowForParams(params);
   TabStripModel* tab_strip_model = browser->tab_strip_model();
 
   LifecycleUnit* tab0 = AddNewTab(tab_strip_model, 0);
@@ -224,7 +224,7 @@
   SetParams({{"disable_background_log_with_TabRanker", "true"}});
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
-      CreateBrowserWithTestWindowForParams(&params);
+      CreateBrowserWithTestWindowForParams(params);
   TabStripModel* tab_strip_model = browser->tab_strip_model();
 
   // Create lifecycleunits.
@@ -331,7 +331,7 @@
 TEST_F(TabMetricsTest, Basic) {
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
-      CreateBrowserWithTestWindowForParams(&params);
+      CreateBrowserWithTestWindowForParams(params);
 
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   content::WebContents* fg_contents =
@@ -374,7 +374,7 @@
 TEST_F(TabMetricsTest, TabEvents) {
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
-      CreateBrowserWithTestWindowForParams(&params);
+      CreateBrowserWithTestWindowForParams(params);
 
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   content::WebContents* test_contents_1 =
@@ -436,7 +436,7 @@
 TEST_F(TabMetricsTest, TabMetrics) {
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
-      CreateBrowserWithTestWindowForParams(&params);
+      CreateBrowserWithTestWindowForParams(params);
 
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   content::WebContents* test_contents_1 =
@@ -506,7 +506,7 @@
 TEST_F(TabMetricsTest, InputEvents) {
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
-      CreateBrowserWithTestWindowForParams(&params);
+      CreateBrowserWithTestWindowForParams(params);
 
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   content::WebContents* test_contents_1 =
@@ -594,7 +594,7 @@
 TEST_F(TabMetricsTest, DISABLED_HideWebContents) {
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
-      CreateBrowserWithTestWindowForParams(&params);
+      CreateBrowserWithTestWindowForParams(params);
 
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   content::WebContents* test_contents =
@@ -617,7 +617,7 @@
 // Tests navigation-related metrics.
 TEST_F(TabMetricsTest, Navigations) {
   Browser::CreateParams params(profile(), true);
-  auto browser = CreateBrowserWithTestWindowForParams(&params);
+  auto browser = CreateBrowserWithTestWindowForParams(params);
   TabStripModel* tab_strip_model = browser->tab_strip_model();
 
   // Set up first tab.
@@ -743,7 +743,7 @@
 TEST_F(TabMetricsTest, ReplaceForegroundTab) {
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
-      CreateBrowserWithTestWindowForParams(&params);
+      CreateBrowserWithTestWindowForParams(params);
 
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   content::WebContents* orig_contents =
@@ -822,7 +822,7 @@
 TEST_F(ForegroundedOrClosedTest, MAYBE_SingleTab) {
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
-      CreateBrowserWithTestWindowForParams(&params);
+      CreateBrowserWithTestWindowForParams(params);
 
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   tab_activity_simulator_.AddWebContentsAndNavigate(tab_strip_model,
@@ -837,7 +837,7 @@
 TEST_F(ForegroundedOrClosedTest, MultipleTabs) {
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
-      CreateBrowserWithTestWindowForParams(&params);
+      CreateBrowserWithTestWindowForParams(params);
 
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   tab_activity_simulator_.AddWebContentsAndNavigate(tab_strip_model,
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_tracing_ui.js b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_tracing_ui.js
index ca63020e..440d3bfa 100644
--- a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_tracing_ui.js
+++ b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_tracing_ui.js
@@ -18,7 +18,7 @@
 // Supported zooms, mcs per pixel
 var zooms = [
   2.5, 5.0, 10.0, 25.0, 50.0, 100.0, 250.0, 500.0, 1000.0, 2500.0, 5000.0,
-  10000.0
+  10000.0, 25000.0
 ];
 
 // Active zoom level, as index in |zooms|. By default 100 mcs per pixel.
@@ -366,20 +366,22 @@
     }
   };
 
-  $('arc-tracing-load').onclick = function(event) {
-    var fileElement = document.createElement('input');
-    fileElement.type = 'file';
+  if ($('arc-tracing-load')) {
+    $('arc-tracing-load').onclick = function(event) {
+      var fileElement = document.createElement('input');
+      fileElement.type = 'file';
 
-    fileElement.onchange = function(event) {
-      var reader = new FileReader();
-      reader.onload = function(response) {
-        chrome.send('loadFromText', [response.target.result]);
+      fileElement.onchange = function(event) {
+        var reader = new FileReader();
+        reader.onload = function(response) {
+          chrome.send('loadFromText', [response.target.result]);
+        };
+        reader.readAsText(event.target.files[0]);
       };
-      reader.readAsText(event.target.files[0]);
-    };
 
-    fileElement.click();
-  };
+      fileElement.click();
+    };
+  }
 }
 
 /**
@@ -788,6 +790,45 @@
     }
   }
 
+  /**
+   * This adds sources of events to the last chart as a bars.
+   *
+   * @param {Events[]} sources is array of groupped source of events to add.
+   *     These events are logically linked to each other and represented as a
+   *     bar where each bar has color corresponded the value of the event.
+   * @param {Object=} attributes dictionary to resolve the color of the bar.
+   * @param {number} y vertical offset of bars.
+   * @param {number} height height of bars.
+   */
+  addBarSource(source, attributes, y, height) {
+    var chart = this.charts[this.charts.length - 1];
+
+    var eventIndex = source.getFirstAfter(this.minTimestamp);
+    if (eventIndex < 0 || source.events[eventIndex][1] > this.maxTimestamp) {
+      return;
+    }
+
+    while (eventIndex >= 0 &&
+           source.events[eventIndex][1] <= this.maxTimestamp) {
+      var eventIndexNext = source.getNextEvent(eventIndex, 1 /* direction */);
+      var event = source.events[eventIndex];
+      var x = this.timestampToOffset(event[1]);
+      var color = attributes[event[2]].color;
+      var nextTimestamp = 0;
+      if (eventIndexNext >= 0 &&
+          source.events[eventIndexNext][1] <= this.maxTimestamp) {
+        nextTimestamp = source.events[eventIndexNext][1];
+      } else {
+        nextTimestamp = this.maxTimestamp;
+      }
+      var width = this.timestampToOffset(nextTimestamp);
+      eventIndex = eventIndexNext;
+      SVG.addRect(this.svg, x, y, width, height, color, 1.0 /* opacity */);
+    }
+    chart.sourcesWithBounds.push(
+        {attributes: attributes, source: source, perValue: true});
+  }
+
   addChartGridLine(y) {
     SVG.addLine(this.svg, 0, y, this.width, y, '#ccc', 0.5);
   }
@@ -1172,32 +1213,47 @@
     var valueOffset = 32;
 
     var contentAdded = false;
-
     for (var i = 0; i < chart.sourcesWithBounds.length; ++i) {
       var sourceWithBounds = chart.sourcesWithBounds[i];
-      // Interpolate results.
-      var indexAfter = sourceWithBounds.source.getFirstAfter(eventTimestamp);
-      if (indexAfter < 0) {
-        continue;
-      }
-      var indexBefore =
-          sourceWithBounds.source.getNextEvent(indexAfter, -1 /* direction */);
-      if (indexBefore < 0) {
-        continue;
-      }
-      var eventBefore = sourceWithBounds.source.events[indexBefore];
-      var eventAfter = sourceWithBounds.source.events[indexAfter];
-      var factor =
-          (eventTimestamp - eventBefore[1]) / (eventAfter[1] - eventBefore[1]);
 
-      if (!sourceWithBounds.smooth) {
-        // Clamp to before value.
-        if (factor < 1.0) {
-          factor = 0.0;
+      var color;
+      var text;
+      if (sourceWithBounds.perValue) {
+        // Tooltip per value
+        var index = sourceWithBounds.source.getLastBefore(eventTimestamp);
+        if (index < 0) {
+          continue;
         }
-      }
-      var value = factor * eventAfter[2] + (1.0 - factor) * eventBefore[2];
+        var event = sourceWithBounds.source.events[index];
+        color = sourceWithBounds.attributes[event[2]].color;
+        text = sourceWithBounds.attributes[event[2]].name;
+      } else {
+        // Interpolate results.
+        var indexAfter = sourceWithBounds.source.getFirstAfter(eventTimestamp);
+        if (indexAfter < 0) {
+          continue;
+        }
+        var indexBefore = sourceWithBounds.source.getNextEvent(
+            indexAfter, -1 /* direction */);
+        if (indexBefore < 0) {
+          continue;
+        }
+        var eventBefore = sourceWithBounds.source.events[indexBefore];
+        var eventAfter = sourceWithBounds.source.events[indexAfter];
+        var factor = (eventTimestamp - eventBefore[1]) /
+            (eventAfter[1] - eventBefore[1]);
 
+        if (!sourceWithBounds.smooth) {
+          // Clamp to before value.
+          if (factor < 1.0) {
+            factor = 0.0;
+          }
+        }
+        var value = factor * eventAfter[2] + (1.0 - factor) * eventBefore[2];
+        text = (value * sourceWithBounds.attributes.scale).toFixed(1) + ' ' +
+            sourceWithBounds.attributes.name;
+        color = sourceWithBounds.attributes.color;
+      }
       if (!contentAdded) {
         yOffset = this.addTimeInfoToTooltip_(svg, yOffset, eventTimestamp);
         contentAdded = true;
@@ -1206,9 +1262,7 @@
       yOffset += this.lineHeight;
       SVG.addCircle(
           svg, this.iconOffset, yOffset - this.iconRadius, this.iconRadius, 1,
-          sourceWithBounds.attributes.color, 'black');
-      var text = (value * sourceWithBounds.attributes.scale).toFixed(1) + ' ' +
-          sourceWithBounds.attributes.name;
+          color, 'black');
       SVG.addText(svg, valueOffset, yOffset, this.fontSize, text);
     }
 
@@ -1507,6 +1561,7 @@
 class CpuEventBands extends EventBands {
   setModel(model) {
     this.model = model;
+    this.showDetailedInfo = true;
     var bandHeight = 6;
     var padding = 2;
     for (var cpuId = 0; cpuId < this.model.system.cpu.length; cpuId++) {
@@ -1516,7 +1571,7 @@
   }
 
   canShowDetailedInfo() {
-    return true;
+    return this.showDetailedInfo;
   }
 
   showDetailedInfo(event) {
diff --git a/chrome/browser/resources/chromeos/arc_power_control/arc_power_control.css b/chrome/browser/resources/chromeos/arc_power_control/arc_power_control.css
new file mode 100644
index 0000000..0141804a
--- /dev/null
+++ b/chrome/browser/resources/chromeos/arc_power_control/arc_power_control.css
@@ -0,0 +1,13 @@
+/* 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. */
+
+
+#arc-power-control-buttons {
+  float: right;
+}
+
+.arc-power-control-vertical-splitter {
+    border-inline-start: 1px solid #888;
+    padding-inline-start: 4px;
+}
diff --git a/chrome/browser/resources/chromeos/arc_power_control/arc_power_control.html b/chrome/browser/resources/chromeos/arc_power_control/arc_power_control.html
new file mode 100644
index 0000000..43b99bd
--- /dev/null
+++ b/chrome/browser/resources/chromeos/arc_power_control/arc_power_control.html
@@ -0,0 +1,50 @@
+<!-- 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. -->
+
+<!doctype html>
+<html>
+  <head>
+    <meta charset=utf-8>
+    <link rel="stylesheet" href="arc_power_control.css">
+    <link rel="stylesheet" href="arc_tracing.css">
+    <script src="chrome://resources/js/cr.js"></script>
+    <script src="chrome://resources/js/cr/ui.js"></script>
+    <script src="chrome://resources/js/util.js"></script>
+    <script src="arc_tracing_ui.js"></script>
+    <script src="arc_power_control.js"></script>
+    <title>ARC power control</title>
+  </head>
+  <body>
+    <div>
+      <h3>ARC power control</h3>
+      Current mode: <i id="arc-power-control-status"></i>
+      <div id="arc-power-control-buttons" hidden>
+        <button type="button" id="arc-power-control-wakeup">Wakeup</button>
+        <button type="button" id="arc-power-control-doze">Doze</button>
+        <button type="button" id="arc-power-control-sleep">Sleep</button>
+        <span class="arc-power-control-vertical-splitter">Throttling<span>
+        <input type="radio" name="arc-power-control-throttling"
+            id="arc-power-control-throttling-disable">Disable</input>
+        <input type="radio" name="arc-power-control-throttling"
+            id="arc-power-control-throttling-auto"
+            checked="checked">Auto</input>
+        <input type="radio" name="arc-power-control-throttling"
+            id="arc-power-control-throttling-force">Force</input>
+      </div>
+    </div>
+    <hr>
+    <div>
+      <h3>ARC system metrics</h3>
+      Status: <i id="arc-tracing-status">Idle</i>
+      <div id="arc-tracing-control-buttons">
+        <button type="button" id="arc-tracing-start">Start</button>
+        <button type="button" id="arc-tracing-stop">Stop</button>
+      </div>
+    </div>
+    <hr>
+    <div id='arc-event-bands'></div>
+    <div id='arc-detailed-view-overlay'></div>
+    <div id='arc-event-band-tooltip'></div>
+  </body>
+</html>
diff --git a/chrome/browser/resources/chromeos/arc_power_control/arc_power_control.js b/chrome/browser/resources/chromeos/arc_power_control/arc_power_control.js
new file mode 100644
index 0000000..ed05a12
--- /dev/null
+++ b/chrome/browser/resources/chromeos/arc_power_control/arc_power_control.js
@@ -0,0 +1,248 @@
+// 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.
+
+/**
+ * @fileoverview ARC Power Control UI root element.
+ */
+
+/**
+ * @type {Object}.
+ * Currently loaded model.
+ */
+var activeModel = null;
+
+/**
+ * Sets current power control status.
+ * @param {string} statusText text to set as a status.
+ */
+function setPowerControlStatus(statusText) {
+  $('arc-power-control-status').textContent = statusText;
+}
+
+/**
+ * Sets current tracing status.
+ * @param {string} statusText text to set as a status.
+ */
+function setTracingStatus(statusText) {
+  $('arc-tracing-status').textContent = statusText;
+}
+
+/**
+ * Sets model to the view and refreshes everything.
+ *
+ * @param {object} model to display.
+ */
+function setModel(model) {
+  activeModel = model;
+  refreshModel();
+}
+
+/**
+ * Sets throttling mode.
+ *
+ * @param {string} name of throttling mode.
+ */
+function setThrottlingMode(mode) {
+  $('arc-power-control-throttling-disable').checked = false;
+  $('arc-power-control-throttling-auto').checked = false;
+  $('arc-power-control-throttling-force').checked = false;
+  $('arc-power-control-throttling-' + mode).checked = true;
+}
+
+/**
+ * Sets enable/disable power control
+ *
+ * @param {enable} true in case ARC power control enabled.
+ */
+function setPowerControlEnabled(enabled) {
+  $('arc-power-control-buttons').hidden = !enabled;
+}
+
+function refreshModel() {
+  // Clear previous content.
+  $('arc-event-bands').textContent = '';
+
+  if (!activeModel) {
+    return;
+  }
+  var duration = activeModel.information.duration;
+
+  // Microseconds per pixel. 100% zoom corresponds to 100 mcs per pixel.
+  var resolution = zooms[zoomLevel];
+  var parent = $('arc-event-bands');
+
+  var topBandPadding = 4;
+  var chartHeight = 96;
+  var barHeight = 12;
+
+  var controlTitle =
+      new EventBandTitle(parent, 'Power control', 'arc-events-band-title');
+  var controlBands =
+      new EventBands(controlTitle, 'arc-events-band', resolution, 0, duration);
+  controlBands.setWidth(controlBands.timestampToOffset(duration));
+  controlBands.addChart(2 * barHeight, topBandPadding);
+
+  var wakenessfullAttributes = {
+    '-1': {color: '#ffc0cb', name: 'Unknown'},
+    0: {color: '#5d5d5d', name: 'Asleep'},
+    1: {color: '#fff0c7', name: 'Awake'},
+    2: {color: '#c7cfff', name: 'Dreaming'},
+    3: {color: '#3e49ed', name: 'Dozing'},
+  };
+  var throttlingAttributes = {
+    0: {color: '#ffc0cb', name: 'Unknown'},
+    1: {color: '#ccc', name: 'Throttling'},
+    2: {color: '#7bed3e', name: 'Foreground'},
+    3: {color: '#7bed3e', name: 'Foreground-important'},
+    4: {color: '#7bed3e', name: 'Foreground-critical'},
+  };
+
+  controlBands.addBarSource(
+      new Events(
+          activeModel.system.memory, 14 /* kWakenessfullMode */,
+          14 /* kWakenessfullMode */),
+      wakenessfullAttributes, 0 /* y */, barHeight);
+  controlBands.addBarSource(
+      new Events(
+          activeModel.system.memory, 15 /* kThrottlingMode */,
+          15 /* kThrottlingMode */),
+      throttlingAttributes, barHeight /* y */, barHeight);
+
+  var cpusTitle = new EventBandTitle(parent, 'CPUs', 'arc-events-band-title');
+  var cpusBands =
+      new CpuEventBands(cpusTitle, 'arc-events-band', resolution, 0, duration);
+  cpusBands.showDetailedInfo = false;
+  cpusBands.setWidth(cpusBands.timestampToOffset(duration));
+  cpusBands.setModel(activeModel);
+  cpusBands.addChart(chartHeight, topBandPadding);
+  cpusBands.addChartSources(
+      [new Events(
+          activeModel.system.memory, 8 /* kCpuTemperature */,
+          8 /* kCpuTemperature */)],
+      true /* smooth */);
+  cpusBands.addChartSources(
+      [new Events(
+          activeModel.system.memory, 9 /* kCpuFrequency */,
+          9 /* kCpuFrequency */)],
+      true /* smooth */);
+  cpusBands.addChartSources(
+      [new Events(
+          activeModel.system.memory, 10 /* kCpuPower */, 10 /* kCpuPower */)],
+      true /* smooth */);
+
+  var memoryTitle =
+      new EventBandTitle(parent, 'Memory', 'arc-events-band-title');
+  var memoryBands =
+      new EventBands(memoryTitle, 'arc-events-band', resolution, 0, duration);
+  memoryBands.setWidth(memoryBands.timestampToOffset(duration));
+  memoryBands.addChart(chartHeight, topBandPadding);
+  // Used memory chart.
+  memoryBands.addChartSources(
+      [new Events(
+          activeModel.system.memory, 1 /* kMemUsed */, 1 /* kMemUsed */)],
+      true /* smooth */);
+  // Swap memory chart.
+  memoryBands.addChartSources(
+      [
+        new Events(
+            activeModel.system.memory, 2 /* kSwapRead */, 2 /* kSwapRead */),
+        new Events(
+            activeModel.system.memory, 3 /* kSwapWrite */, 3 /* kSwapWrite */)
+      ],
+      true /* smooth */);
+  // Geom objects and size.
+  memoryBands.addChartSources(
+      [new Events(
+          activeModel.system.memory, 5 /* kGemObjects */, 5 /* kGemObjects */)],
+      true /* smooth */);
+  memoryBands.addChartSources(
+      [new Events(
+          activeModel.system.memory, 6 /* kGemSize */, 6 /* kGemSize */)],
+      true /* smooth */);
+  memoryBands.addChartSources(
+      [new Events(
+          activeModel.system.memory, 12 /* kMemoryPower */,
+          12 /* kMemoryPower */)],
+      true /* smooth */);
+
+  var chromeTitle =
+      new EventBandTitle(parent, 'Chrome graphics', 'arc-events-band-title');
+  var chromeBands =
+      new EventBands(chromeTitle, 'arc-events-band', resolution, 0, duration);
+  chromeBands.setWidth(chromeBands.timestampToOffset(duration));
+  chromeBands.addChart(chartHeight, topBandPadding);
+  chromeBands.addChartSources(
+      [new Events(
+          activeModel.system.memory, 7 /* kGpuFrequency */,
+          7 /* kGpuFrequency */)],
+      false /* smooth */);
+  chromeBands.addChartSources(
+      [new Events(
+          activeModel.system.memory, 11 /* kGpuPower */, 11 /* kGpuPower */)],
+      true /* smooth */);
+}
+
+cr.define('cr.ArcPowerControl', function() {
+  return {
+    /**
+     * Initializes internal structures.
+     */
+    initialize() {
+      // Wakefulness mode
+      $('arc-power-control-wakeup').onclick = function(event) {
+        chrome.send('setWakefulnessMode', ['wakeup']);
+      };
+      $('arc-power-control-doze').onclick = function(event) {
+        chrome.send('setWakefulnessMode', ['doze']);
+      };
+      $('arc-power-control-sleep').onclick = function(event) {
+        chrome.send('setWakefulnessMode', ['sleep']);
+      };
+      $('arc-power-control-sleep').onclick = function(event) {
+        chrome.send('setWakefulnessMode', ['sleep']);
+      };
+      // Throttling control
+      $('arc-power-control-throttling-disable').onclick = function(event) {
+        chrome.send('setThrottling', ['disable']);
+      };
+      $('arc-power-control-throttling-auto').onclick = function(event) {
+        chrome.send('setThrottling', ['auto']);
+      };
+      $('arc-power-control-throttling-force').onclick = function(event) {
+        chrome.send('setThrottling', ['force']);
+      };
+      // Tracing control
+      $('arc-tracing-start').onclick = function(event) {
+        chrome.send('startTracing');
+      };
+      $('arc-tracing-stop').onclick = function(event) {
+        chrome.send('stopTracing');
+      };
+
+      initializeUi(10 /* zoomLevel */, function() {
+        // Update function.
+        refreshModel();
+      });
+
+      chrome.send('ready');
+    },
+
+    setPowerControlStatus: setPowerControlStatus,
+
+    setTracingStatus: setTracingStatus,
+
+    setThrottlingMode: setThrottlingMode,
+
+    setPowerControlEnabled: setPowerControlEnabled,
+
+    setModel: setModel,
+  };
+});
+
+/**
+ * Initializes UI.
+ */
+window.onload = function() {
+  cr.ArcPowerControl.initialize();
+};
diff --git a/chrome/browser/resources/chromeos/login/BUILD.gn b/chrome/browser/resources/chromeos/login/BUILD.gn
index 7ddffe24..4f2e722b 100644
--- a/chrome/browser/resources/chromeos/login/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/BUILD.gn
@@ -39,6 +39,7 @@
     ":oobe_supervision_transition",
     ":oobe_update",
     ":oobe_welcome",
+    ":parental_handoff",
     ":recommend_apps",
     ":saml_confirm_password",
     ":sync_consent",
@@ -275,6 +276,14 @@
   ]
 }
 
+js_library("parental_handoff") {
+  deps = [
+    "components:login_screen_behavior",
+    "components:oobe_dialog_host_behavior",
+    "components:oobe_i18n_behavior",
+  ]
+}
+
 js_library("recommend_apps") {
   deps = [
     "components:login_screen_behavior",
diff --git a/chrome/browser/resources/chromeos/login/parental_handoff.html b/chrome/browser/resources/chromeos/login/parental_handoff.html
new file mode 100644
index 0000000..9ba88fa5
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/parental_handoff.html
@@ -0,0 +1,37 @@
+<!-- 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. -->
+
+<link rel="import" href="chrome://oobe/custom_elements.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+
+<dom-module id="parental-handoff">
+  <template>
+    <style include="oobe-dialog-host"></style>
+    <oobe-dialog id="parentalHandoffDialog" role="dialog" has-buttons
+        aria-label$="[[title_]]">
+      <hd-iron-icon icon1x="oobe-32:googleg" icon2x="oobe-64:googleg"
+          slot="oobe-icon">
+      </hd-iron-icon>
+      <h1 slot="title">
+        [[title_]]
+      </h1>
+      <div slot="subtitle">
+        [[subtitle_]]
+      </div>
+      <div slot="footer" class="flex layout vertical center center-justified">
+        <!-- TODO(yilkal): Replace the following image when the appropriate
+             image is ready to be used -->
+        <img srcset="images/1x/parental_control.svg 1x,
+            images/2x/parental_control.svg 2x" class="oobe-illustration"
+            alt$="[[title_]]">
+      </div>
+      <div slot="bottom-buttons" class="layout horizontal end-justified">
+        <oobe-next-button id="nextButton"
+            text-key="parentalHandoffDialogNextButton" class="focus-on-show"
+            inverse on-click="onNextButtonPressed_"></oobe-next-button>
+      </div>
+    </oobe-dialog>
+  </template>
+</dom-module>
diff --git a/chrome/browser/resources/chromeos/login/parental_handoff.js b/chrome/browser/resources/chromeos/login/parental_handoff.js
new file mode 100644
index 0000000..cbe7e2c5
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/parental_handoff.js
@@ -0,0 +1,68 @@
+// 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.
+
+/**
+ * @fileoverview Polymer element for Parental Handoff screen.
+ */
+
+Polymer({
+  is: 'parental-handoff',
+
+  behaviors: [OobeI18nBehavior, OobeDialogHostBehavior, LoginScreenBehavior],
+
+  properties: {
+    /**
+     * THe title to be displayed
+     */
+    title_: {
+      type: String,
+      value: '',
+    },
+
+    /**
+     * The subtitle to be displayed.
+     */
+    subtitle_: {
+      type: String,
+      value: '',
+    },
+  },
+
+  /**
+   * Event handler that is invoked just before the frame is shown.
+   * @param {Object} data Screen init payload
+   */
+  onBeforeShow(data) {
+    if ('title' in data) {
+      this.title_ = data.title;
+    }
+
+    if ('subtitle' in data) {
+      this.subtitle_ = data.subtitle;
+    }
+  },
+
+  ready() {
+    this.initializeLoginScreen('ParentalHandoffScreen', {
+      resetAllowed: true,
+    });
+  },
+
+  /*
+   * Executed on language change.
+   */
+  updateLocalizedContent() {
+    this.i18nUpdateLocale();
+  },
+
+  /**
+   * On-tap event handler for Next button.
+   *
+   * @private
+   */
+  onNextButtonPressed_() {
+    this.userActed('next');
+  },
+
+});
diff --git a/chrome/browser/resources/chromeos/login/structure/components_common.html b/chrome/browser/resources/chromeos/login/structure/components_common.html
index 6523a5b..3d5680d0 100644
--- a/chrome/browser/resources/chromeos/login/structure/components_common.html
+++ b/chrome/browser/resources/chromeos/login/structure/components_common.html
@@ -54,6 +54,7 @@
 <include src="../family_link_notice.html">
 <include src="../user_creation.html">
 <include src="../screen_signin_fatal_error.html">
+<include src="../parental_handoff.html">
 
 <include src="components_[OOBE].html">
 
diff --git a/chrome/browser/resources/chromeos/login/structure/components_common.js b/chrome/browser/resources/chromeos/login/structure/components_common.js
index 427f2aca..a0e132d 100644
--- a/chrome/browser/resources/chromeos/login/structure/components_common.js
+++ b/chrome/browser/resources/chromeos/login/structure/components_common.js
@@ -53,5 +53,6 @@
 // <include src="../family_link_notice.js">
 // <include src="../user_creation.js">
 // <include src="../screen_signin_fatal_error.js">
+// <include src="../parental_handoff.js">
 
 // <include src="components_[OOBE].js">
diff --git a/chrome/browser/resources/chromeos/login/structure/screens_common.html b/chrome/browser/resources/chromeos/login/structure/screens_common.html
index 934c0466..e80800f 100644
--- a/chrome/browser/resources/chromeos/login/structure/screens_common.html
+++ b/chrome/browser/resources/chromeos/login/structure/screens_common.html
@@ -45,3 +45,5 @@
 </family-link-notice>
 <user-creation id="user-creation" class="step hidden">
 </user-creation>
+<parental-handoff id="parental-handoff" class="step hidden">
+</parental-handoff>
diff --git a/chrome/browser/resources/read_later/app.js b/chrome/browser/resources/read_later/app.js
index 6b5162d..c92d119 100644
--- a/chrome/browser/resources/read_later/app.js
+++ b/chrome/browser/resources/read_later/app.js
@@ -43,6 +43,12 @@
   ready() {
     super.ready();
     this.updateItems_();
+    // Push ShowUI() callback to the event queue to allow deferred rendering to
+    // take place.
+    // TODO(corising): Determine the ideal place to make this call.
+    setTimeout(() => {
+      this.apiProxy_.showUI();
+    }, 0);
   }
 
   /** @override */
diff --git a/chrome/browser/resources/read_later/read_later_api_proxy.js b/chrome/browser/resources/read_later/read_later_api_proxy.js
index 619803ab..b5a6594 100644
--- a/chrome/browser/resources/read_later/read_later_api_proxy.js
+++ b/chrome/browser/resources/read_later/read_later_api_proxy.js
@@ -28,6 +28,8 @@
   /** @param {!url.mojom.Url} url */
   removeEntry(url) {}
 
+  showUI() {}
+
   /** @return {!readLater.mojom.PageCallbackRouter} */
   getCallbackRouter() {}
 }
@@ -68,6 +70,11 @@
   }
 
   /** @override */
+  showUI() {
+    this.handler.showUI();
+  }
+
+  /** @override */
   getCallbackRouter() {
     return this.callbackRouter;
   }
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_section.html b/chrome/browser/resources/settings/autofill_page/passwords_section.html
index 737197e7..6bbb244 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_section.html
+++ b/chrome/browser/resources/settings/autofill_page/passwords_section.html
@@ -206,7 +206,9 @@
                 $i18n{devicePasswordsLinkSubLabel}
               </div>
             </div>
-            <cr-icon-button iron-icon="cr:arrow-right"></cr-icon-button>
+            <cr-icon-button iron-icon="cr:arrow-right"
+                aria-roledescription="$i18n{subpageArrowRoleDescription}">
+            </cr-icon-button>
           </div>
         </div>
         <div id="savedPasswordsHeaders" class="list-item column-header"
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/tether_connection_dialog.html b/chrome/browser/resources/settings/chromeos/internet_page/tether_connection_dialog.html
index c2cc0772..3a34825 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/tether_connection_dialog.html
+++ b/chrome/browser/resources/settings/chromeos/internet_page/tether_connection_dialog.html
@@ -79,8 +79,7 @@
         <div id="host-device-container">
           <iron-icon id="host-device-signal-strength-icon"
               icon="[[getSignalStrengthIconName_(managedProperties)]]"
-              aria-label$="[[getSignalStrengthLabel_(managedProperties)]]"
-              aria-hidden="true">
+              aria-label$="[[getSignalStrengthLabel_(managedProperties)]]">
           </iron-icon>
           <div id="host-device-text-container">
             <span id="host-device-text-name"
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.html b/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.html
index 5dbc17fd..dd2c395 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.html
@@ -149,7 +149,8 @@
             learn-more-url="$i18n{syncAndGoogleServicesLearnMoreURL}">
           <settings-sync-page
               sync-status="[[syncStatus]]" prefs="{{prefs}}"
-              page-visibility="[[pageVisibility.privacy]]">
+              page-visibility="[[pageVisibility.privacy]]"
+              focus-config="[[focusConfig_]]">
           </settings-sync-page>
         </settings-subpage>
       </template>
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_child.html b/chrome/browser/resources/settings/safety_check_page/safety_check_child.html
index cd8f974..65b226a 100644
--- a/chrome/browser/resources/settings/safety_check_page/safety_check_child.html
+++ b/chrome/browser/resources/settings/safety_check_page/safety_check_child.html
@@ -60,9 +60,10 @@
   </template>
   <template is="dom-if" if="[[rowClickable]]">
     <cr-icon-button id="rowClickableIndicator"
-        iron-icon="[[getRowClickableIcon_(external)]]"
+        iron-icon="[[rowClickableIcon_]]"
         aria-describedby="subLabel"
-        aria-labelledby="label">
+        aria-labelledby="label"
+        aria-roledescription$="[[getRoleDescription_(rowClickableIcon_)]]">
     </cr-icon-button>
   </template>
 </div>
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_child.js b/chrome/browser/resources/settings/safety_check_page/safety_check_child.js
index 11de2b41..51940cb0 100644
--- a/chrome/browser/resources/settings/safety_check_page/safety_check_child.js
+++ b/chrome/browser/resources/settings/safety_check_page/safety_check_child.js
@@ -75,6 +75,11 @@
       value: false,
     },
 
+    rowClickableIcon_: {
+      type: String,
+      computed: 'computeRowClickableIcon_(external)',
+    },
+
     // Right hand managed icon. |null| removes it from the DOM.
     managedIcon: String,
   },
@@ -176,7 +181,18 @@
    * @return {string}
    * @private
    */
-  getRowClickableIcon_() {
+  computeRowClickableIcon_() {
     return this.external ? 'cr:open-in-new' : 'cr:arrow-right';
   },
+
+  /**
+   * Return the subpage role description if the arrow right icon is used.
+   * @return {string}
+   * @private
+   */
+  getRoleDescription_() {
+    return this.rowClickableIcon_ === 'cr:arrow-right' ?
+        this.i18n('subpageArrowRoleDescription') :
+        '';
+  }
 });
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn
index 17158c9..16d5e5a7 100644
--- a/chrome/browser/safe_browsing/BUILD.gn
+++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -73,10 +73,6 @@
     # "Safe Browsing Basic" files used for safe browsing in full mode
     # (safe_browsing=1) and mobile (=2)
     sources += [
-      "browser_feature_extractor.cc",
-      "browser_feature_extractor.h",
-      "browser_features.cc",
-      "browser_features.h",
       "certificate_reporting_metrics_provider.cc",
       "certificate_reporting_metrics_provider.h",
       "certificate_reporting_service.cc",
diff --git a/chrome/browser/safe_browsing/browser_feature_extractor.cc b/chrome/browser/safe_browsing/browser_feature_extractor.cc
deleted file mode 100644
index 5fac9a6..0000000
--- a/chrome/browser/safe_browsing/browser_feature_extractor.cc
+++ /dev/null
@@ -1,360 +0,0 @@
-// Copyright (c) 2012 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/safe_browsing/browser_feature_extractor.h"
-
-#include <stddef.h>
-
-#include <map>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/format_macros.h"
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/task/post_task.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "chrome/browser/history/history_service_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/safe_browsing/browser_features.h"
-#include "chrome/browser/safe_browsing/client_side_detection_host.h"
-#include "components/history/core/browser/history_service.h"
-#include "components/history/core/browser/history_types.h"
-#include "components/safe_browsing/core/proto/csd.pb.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/base/page_transition_types.h"
-#include "url/gurl.h"
-
-using content::BrowserThread;
-using content::NavigationController;
-using content::NavigationEntry;
-using content::WebContents;
-
-namespace safe_browsing {
-
-BrowseInfo::BrowseInfo() : http_status_code(0) {}
-
-BrowseInfo::~BrowseInfo() {}
-
-static void AddFeature(const std::string& feature_name,
-                       double feature_value,
-                       ClientPhishingRequest* request) {
-  DCHECK(request);
-  ClientPhishingRequest::Feature* feature =
-      request->add_non_model_feature_map();
-  feature->set_name(feature_name);
-  feature->set_value(feature_value);
-  DVLOG(2) << "Browser feature: " << feature->name() << " " << feature->value();
-}
-
-static void AddNavigationFeatures(const std::string& feature_prefix,
-                                  NavigationController* controller,
-                                  int index,
-                                  const std::vector<GURL>& redirect_chain,
-                                  ClientPhishingRequest* request) {
-  NavigationEntry* entry = controller->GetEntryAtIndex(index);
-  bool is_secure_referrer = entry->GetReferrer().url.SchemeIsCryptographic();
-  if (!is_secure_referrer) {
-    AddFeature(base::StringPrintf("%s%s=%s", feature_prefix.c_str(), kReferrer,
-                                  entry->GetReferrer().url.spec().c_str()),
-               1.0, request);
-  }
-  AddFeature(feature_prefix + kHasSSLReferrer, is_secure_referrer ? 1.0 : 0.0,
-             request);
-  AddFeature(feature_prefix + kPageTransitionType,
-             static_cast<double>(
-                 ui::PageTransitionStripQualifier(entry->GetTransitionType())),
-             request);
-  AddFeature(feature_prefix + kIsFirstNavigation, index == 0 ? 1.0 : 0.0,
-             request);
-  // Redirect chain should always be at least of size one, as the rendered
-  // url is the last element in the chain.
-  if (redirect_chain.empty()) {
-    NOTREACHED();
-    return;
-  }
-  if (redirect_chain.back() != entry->GetURL()) {
-    // I originally had this as a DCHECK but I saw a failure once that I
-    // can't reproduce. It looks like it might be related to the
-    // navigation controller only keeping a limited number of navigation
-    // events. For now we'll just attach a feature specifying that this is
-    // a mismatch and try and figure out what to do with it on the server.
-    DLOG(WARNING) << "Expected:" << entry->GetURL()
-                 << " Actual:" << redirect_chain.back();
-    AddFeature(feature_prefix + kRedirectUrlMismatch, 1.0, request);
-    return;
-  }
-  // We skip the last element since it should just be the current url.
-  for (size_t i = 0; i < redirect_chain.size() - 1; i++) {
-    std::string printable_redirect = redirect_chain[i].spec();
-    if (redirect_chain[i].SchemeIsCryptographic()) {
-      printable_redirect = kSecureRedirectValue;
-    }
-    AddFeature(base::StringPrintf("%s%s[%" PRIuS "]=%s", feature_prefix.c_str(),
-                                  kRedirect, i, printable_redirect.c_str()),
-               1.0, request);
-  }
-}
-
-BrowserFeatureExtractor::BrowserFeatureExtractor(WebContents* tab) : tab_(tab) {
-  DCHECK(tab);
-}
-
-BrowserFeatureExtractor::~BrowserFeatureExtractor() {
-  weak_factory_.InvalidateWeakPtrs();
-}
-
-void BrowserFeatureExtractor::ExtractFeatures(
-    const BrowseInfo* info,
-    std::unique_ptr<ClientPhishingRequest> request,
-    DoneCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(request);
-  DCHECK(info);
-  DCHECK(GURL(request->url()).SchemeIsHTTPOrHTTPS());
-  DCHECK(!callback.is_null());
-  // Extract features pertaining to this navigation.
-  NavigationController& controller = tab_->GetController();
-  int url_index = -1;
-  int first_host_index = -1;
-
-  GURL request_url(request->url());
-  int index = controller.GetCurrentEntryIndex();
-  // The url that we are extracting features for should already be commited.
-  DCHECK_NE(index, -1);
-  for (; index >= 0; index--) {
-    NavigationEntry* entry = controller.GetEntryAtIndex(index);
-    if (url_index == -1 && entry->GetURL() == request_url) {
-      // It's possible that we've been on the on the possibly phishy url before
-      // in this tab, so make sure that we use the latest navigation for
-      // features.
-      // Note that it's possible that the url_index should always be the
-      // latest entry, but I'm worried about possible races during a navigation
-      // and transient entries (i.e. interstiatials) so for now we will just
-      // be cautious.
-      url_index = index;
-    } else if (index < url_index) {
-      if (entry->GetURL().host_piece() == request_url.host_piece()) {
-        first_host_index = index;
-      } else {
-        // We have found the possibly phishing url, but we are no longer on the
-        // host. No reason to look back any further.
-        break;
-      }
-    }
-  }
-
-  // Add features pertaining to how we got to
-  //   1) The candidate url
-  //   2) The first url on the same host as the candidate url (assuming that
-  //      it's different from the candidate url).
-  if (url_index != -1) {
-    AddNavigationFeatures(std::string(), &controller, url_index,
-                          info->url_redirects, request.get());
-  }
-  if (first_host_index != -1) {
-    AddNavigationFeatures(kHostPrefix, &controller, first_host_index,
-                          info->host_redirects, request.get());
-  }
-
-  ExtractBrowseInfoFeatures(*info, request.get());
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&BrowserFeatureExtractor::StartExtractFeatures,
-                                weak_factory_.GetWeakPtr(), std::move(request),
-                                std::move(callback)));
-}
-
-void BrowserFeatureExtractor::ExtractBrowseInfoFeatures(
-    const BrowseInfo& info,
-    ClientPhishingRequest* request) {
-  if (info.unsafe_resource.get()) {
-    // A SafeBrowsing interstitial was shown for the current URL.
-    AddFeature(kSafeBrowsingMaliciousUrl + info.unsafe_resource->url.spec(),
-               1.0, request);
-    AddFeature(
-        kSafeBrowsingOriginalUrl + info.unsafe_resource->original_url.spec(),
-        1.0, request);
-    AddFeature(kSafeBrowsingIsSubresource,
-               info.unsafe_resource->is_subresource ? 1.0 : 0.0, request);
-    AddFeature(kSafeBrowsingThreatType,
-               static_cast<double>(info.unsafe_resource->threat_type), request);
-  }
-  if (info.http_status_code != 0) {
-    AddFeature(kHttpStatusCode, info.http_status_code, request);
-  }
-}
-
-void BrowserFeatureExtractor::StartExtractFeatures(
-    std::unique_ptr<ClientPhishingRequest> request,
-    DoneCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  history::HistoryService* history;
-  if (!request || !request->IsInitialized() || !GetHistoryService(&history)) {
-    std::move(callback).Run(/*feature_extraction_succeeded=*/false,
-                            std::move(request));
-    return;
-  }
-  GURL request_url(request->url());
-  history->QueryURL(
-      request_url, true /* wants_visits */,
-      base::BindOnce(&BrowserFeatureExtractor::QueryUrlHistoryDone,
-                     base::Unretained(this), std::move(request),
-                     std::move(callback)),
-      &cancelable_task_tracker_);
-}
-
-void BrowserFeatureExtractor::QueryUrlHistoryDone(
-    std::unique_ptr<ClientPhishingRequest> request,
-    DoneCallback callback,
-    history::QueryURLResult result) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(request);
-  DCHECK(!callback.is_null());
-  if (!result.success) {
-    // URL is not found in the history.  In practice this should not
-    // happen (unless there is a real error) because we just visited
-    // that URL.
-    std::move(callback).Run(/*feature_extraction_succeeded=*/false,
-                            std::move(request));
-    return;
-  }
-  AddFeature(kUrlHistoryVisitCount,
-             static_cast<double>(result.row.visit_count()), request.get());
-
-  base::Time threshold = base::Time::Now() - base::TimeDelta::FromDays(1);
-  int num_visits_24h_ago = 0;
-  int num_visits_typed = 0;
-  int num_visits_link = 0;
-  for (auto& visit : result.visits) {
-    if (!ui::PageTransitionIsMainFrame(visit.transition)) {
-      continue;
-    }
-    if (visit.visit_time < threshold) {
-      ++num_visits_24h_ago;
-    }
-    if (ui::PageTransitionCoreTypeIs(visit.transition,
-                                     ui::PAGE_TRANSITION_TYPED)) {
-      ++num_visits_typed;
-    } else if (ui::PageTransitionCoreTypeIs(visit.transition,
-                                            ui::PAGE_TRANSITION_LINK)) {
-      ++num_visits_link;
-    }
-  }
-  AddFeature(kUrlHistoryVisitCountMoreThan24hAgo,
-             static_cast<double>(num_visits_24h_ago), request.get());
-  AddFeature(kUrlHistoryTypedCount, static_cast<double>(num_visits_typed),
-             request.get());
-  AddFeature(kUrlHistoryLinkCount, static_cast<double>(num_visits_link),
-             request.get());
-
-  // Issue next history lookup for host visits.
-  history::HistoryService* history;
-  if (!GetHistoryService(&history)) {
-    std::move(callback).Run(/*feature_extraction_succeeded=*/false,
-                            std::move(request));
-    return;
-  }
-  GURL::Replacements rep;
-  rep.SetSchemeStr(url::kHttpScheme);
-  GURL http_url = GURL(request->url()).ReplaceComponents(rep);
-  history->GetVisibleVisitCountToHost(
-      http_url,
-      base::BindOnce(&BrowserFeatureExtractor::QueryHttpHostVisitsDone,
-                     base::Unretained(this), std::move(request),
-                     std::move(callback)),
-      &cancelable_task_tracker_);
-}
-
-void BrowserFeatureExtractor::QueryHttpHostVisitsDone(
-    std::unique_ptr<ClientPhishingRequest> request,
-    DoneCallback callback,
-    history::VisibleVisitCountToHostResult result) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(request);
-  DCHECK(!callback.is_null());
-  if (!result.success) {
-    std::move(callback).Run(/*feature_extraction_succeeded=*/false,
-                            std::move(request));
-    return;
-  }
-  SetHostVisitsFeatures(result.count, result.first_visit, true, request.get());
-
-  // Same lookup but for the HTTPS URL.
-  history::HistoryService* history;
-  if (!GetHistoryService(&history)) {
-    std::move(callback).Run(/*feature_extraction_succeeded=*/false,
-                            std::move(request));
-    return;
-  }
-  GURL::Replacements rep;
-  rep.SetSchemeStr(url::kHttpsScheme);
-  GURL https_url = GURL(request->url()).ReplaceComponents(rep);
-  history->GetVisibleVisitCountToHost(
-      https_url,
-      base::BindOnce(&BrowserFeatureExtractor::QueryHttpsHostVisitsDone,
-                     base::Unretained(this), std::move(request),
-                     std::move(callback)),
-      &cancelable_task_tracker_);
-}
-
-void BrowserFeatureExtractor::QueryHttpsHostVisitsDone(
-    std::unique_ptr<ClientPhishingRequest> request,
-    DoneCallback callback,
-    history::VisibleVisitCountToHostResult result) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(request);
-  DCHECK(!callback.is_null());
-  if (!result.success) {
-    std::move(callback).Run(/*feature_extraction_succeeded=*/false,
-                            std::move(request));
-    return;
-  }
-  SetHostVisitsFeatures(result.count, result.first_visit, false, request.get());
-  std::move(callback).Run(/*feature_extraction_succeeded=*/true,
-                          std::move(request));
-}
-
-void BrowserFeatureExtractor::SetHostVisitsFeatures(
-    int num_visits,
-    base::Time first_visit,
-    bool is_http_query,
-    ClientPhishingRequest* request) {
-  DCHECK(request);
-  AddFeature(is_http_query ? kHttpHostVisitCount : kHttpsHostVisitCount,
-             static_cast<double>(num_visits), request);
-  if (num_visits > 0) {
-    AddFeature(
-        is_http_query ? kFirstHttpHostVisitMoreThan24hAgo
-                      : kFirstHttpsHostVisitMoreThan24hAgo,
-        (first_visit < (base::Time::Now() - base::TimeDelta::FromDays(1)))
-            ? 1.0
-            : 0.0,
-        request);
-  }
-}
-
-bool BrowserFeatureExtractor::GetHistoryService(
-    history::HistoryService** history) {
-  *history = NULL;
-  if (tab_ && tab_->GetBrowserContext()) {
-    Profile* profile = Profile::FromBrowserContext(tab_->GetBrowserContext());
-    *history = HistoryServiceFactory::GetForProfile(
-        profile, ServiceAccessType::EXPLICIT_ACCESS);
-    if (*history) {
-      return true;
-    }
-  }
-  DVLOG(2) << "Unable to query history.  No history service available.";
-  return false;
-}
-
-}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/browser_feature_extractor.h b/chrome/browser/safe_browsing/browser_feature_extractor.h
deleted file mode 100644
index 385437d..0000000
--- a/chrome/browser/safe_browsing/browser_feature_extractor.h
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2011 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.
-//
-// BrowserFeatureExtractor computes various browser features for client-side
-// phishing detection.  For now it does a bunch of lookups in the history
-// service to see whether a particular URL has been visited before by the
-// user.
-
-#ifndef CHROME_BROWSER_SAFE_BROWSING_BROWSER_FEATURE_EXTRACTOR_H_
-#define CHROME_BROWSER_SAFE_BROWSING_BROWSER_FEATURE_EXTRACTOR_H_
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/task/cancelable_task_tracker.h"
-#include "base/time/time.h"
-#include "components/history/core/browser/history_types.h"
-#include "components/security_interstitials/core/unsafe_resource.h"
-#include "url/gurl.h"
-
-namespace content {
-class WebContents;
-}
-
-namespace history {
-class HistoryService;
-struct VisibleVisitCountToHostResult;
-struct QueryURLResult;
-}
-
-namespace safe_browsing {
-class ClientPhishingRequest;
-
-struct BrowseInfo {
-  // The URL we're currently browsing.
-  GURL url;
-
-  // If a SafeBrowsing interstitial was shown for the current URL
-  // this will contain the UnsafeResource struct for that URL.
-  std::unique_ptr<security_interstitials::UnsafeResource> unsafe_resource;
-
-  // List of redirects that lead to the first page on the current host and
-  // the current url respectively. These may be the same if the current url
-  // is the first page on its host.
-  std::vector<GURL> host_redirects;
-  std::vector<GURL> url_redirects;
-
-  // URL of the referrer of this URL load.
-  GURL referrer;
-
-  // The HTTP status code from this navigation.
-  int http_status_code;
-
-  BrowseInfo();
-  ~BrowseInfo();
-};
-
-// All methods of this class must be called on the UI thread (including
-// the constructor).
-class BrowserFeatureExtractor {
- public:
-  // Called when feature extraction is done.  The first argument will be
-  // true iff feature extraction succeeded.  The second argument is the
-  // phishing request which was modified by the feature extractor.
-  using DoneCallback =
-      base::OnceCallback<void(bool feature_extraction_succeeded,
-                              std::unique_ptr<ClientPhishingRequest> request)>;
-
-  // The caller keeps ownership of the tab and host objects and is
-  // responsible for ensuring that they stay valid for the entire
-  // lifetime of this object.
-  explicit BrowserFeatureExtractor(content::WebContents* tab);
-
-  // The destructor will cancel any pending requests.
-  virtual ~BrowserFeatureExtractor();
-
-  // Begins extraction of the browser features.  We take ownership
-  // of the request object until |callback| is called (see DoneCallback above)
-  // and will write the extracted features to the feature map.  Once the
-  // feature extraction is complete, |callback| is run on the UI thread.  We
-  // take ownership of the |callback| object.  |info| may not be valid after
-  // ExtractFeatures returns.  This method must run on the UI thread.
-  virtual void ExtractFeatures(const BrowseInfo* info,
-                               std::unique_ptr<ClientPhishingRequest> request,
-                               DoneCallback callback);
-
- private:
-  // Synchronous browser feature extraction.
-  void ExtractBrowseInfoFeatures(const BrowseInfo& info,
-                                 ClientPhishingRequest* request);
-
-  // Actually starts feature extraction (does the real work).
-  void StartExtractFeatures(std::unique_ptr<ClientPhishingRequest> request,
-                            DoneCallback callback);
-
-  // HistoryService callback which is called when we're done querying URL visits
-  // in the history.
-  void QueryUrlHistoryDone(std::unique_ptr<ClientPhishingRequest> request,
-                           DoneCallback callback,
-                           history::QueryURLResult result);
-
-  // HistoryService callback which is called when we're done querying HTTP host
-  // visits in the history.
-  void QueryHttpHostVisitsDone(std::unique_ptr<ClientPhishingRequest> request,
-                               DoneCallback callback,
-                               history::VisibleVisitCountToHostResult result);
-
-  // HistoryService callback which is called when we're done querying HTTPS host
-  // visits in the history.
-  void QueryHttpsHostVisitsDone(std::unique_ptr<ClientPhishingRequest> request,
-                                DoneCallback callback,
-                                history::VisibleVisitCountToHostResult result);
-
-  // Helper function which sets the host history features given the
-  // number of host visits and the time of the fist host visit.  Set
-  // |is_http_query| to true if the URL scheme is HTTP and to false if
-  // the scheme is HTTPS.
-  void SetHostVisitsFeatures(int num_visits,
-                             base::Time first_visit,
-                             bool is_http_query,
-                             ClientPhishingRequest* request);
-
-  // Helper function which gets the history server if possible.  If the pointer
-  // is set it will return true and false otherwise.
-  bool GetHistoryService(history::HistoryService** history);
-
-  content::WebContents* tab_;
-  base::CancelableTaskTracker cancelable_task_tracker_;
-  base::WeakPtrFactory<BrowserFeatureExtractor> weak_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(BrowserFeatureExtractor);
-};
-
-}  // namespace safe_browsing
-#endif  // CHROME_BROWSER_SAFE_BROWSING_BROWSER_FEATURE_EXTRACTOR_H_
diff --git a/chrome/browser/safe_browsing/browser_feature_extractor_unittest.cc b/chrome/browser/safe_browsing/browser_feature_extractor_unittest.cc
deleted file mode 100644
index 9b05a33..0000000
--- a/chrome/browser/safe_browsing/browser_feature_extractor_unittest.cc
+++ /dev/null
@@ -1,553 +0,0 @@
-// Copyright (c) 2012 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/safe_browsing/browser_feature_extractor.h"
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/strings/stringprintf.h"
-#include "base/time/time.h"
-#include "chrome/browser/history/history_service_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/safe_browsing/browser_features.h"
-#include "chrome/browser/safe_browsing/client_side_detection_host.h"
-#include "chrome/browser/safe_browsing/safe_browsing_service.h"
-#include "chrome/browser/safe_browsing/ui_manager.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/history/core/browser/history_backend.h"
-#include "components/history/core/browser/history_service.h"
-#include "components/safe_browsing/core/proto/csd.pb.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/referrer.h"
-#include "content/public/test/navigation_simulator.h"
-#include "content/public/test/web_contents_tester.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/page_transition_types.h"
-#include "url/gurl.h"
-
-using content::BrowserThread;
-using content::WebContentsTester;
-
-using testing::DoAll;
-using testing::Return;
-using testing::StrictMock;
-
-namespace safe_browsing {
-
-namespace {
-
-class MockClientSideDetectionHost : public ClientSideDetectionHost {
- public:
-  explicit MockClientSideDetectionHost(content::WebContents* tab)
-      : ClientSideDetectionHost(tab) {}
-
-  ~MockClientSideDetectionHost() override = default;
-
-  void DidFinishNavigation(
-      content::NavigationHandle* navigation_handle) override {}
-};
-}  // namespace
-
-class BrowserFeatureExtractorTest : public ChromeRenderViewHostTestHarness {
- protected:
-  template <typename Request>
-  struct RequestAndResult {
-    std::unique_ptr<Request> request;
-    bool success = false;
-  };
-
-  void SetUp() override {
-    ChromeRenderViewHostTestHarness::SetUp();
-    ASSERT_TRUE(profile()->CreateHistoryService());
-
-    host_.reset(new StrictMock<MockClientSideDetectionHost>(web_contents()));
-    extractor_.reset(new BrowserFeatureExtractor(web_contents()));
-    num_pending_ = 0;
-    browse_info_.reset(new BrowseInfo);
-  }
-
-  void TearDown() override {
-    extractor_.reset();
-    host_.reset();
-    ChromeRenderViewHostTestHarness::TearDown();
-    ASSERT_EQ(0, num_pending_);
-  }
-
-  history::HistoryService* history_service() {
-    return HistoryServiceFactory::GetForProfile(
-        profile(), ServiceAccessType::EXPLICIT_ACCESS);
-  }
-
-  void SetRedirectChain(const std::vector<GURL>& redirect_chain,
-                        bool new_host) {
-    browse_info_->url_redirects = redirect_chain;
-    if (new_host) {
-      browse_info_->host_redirects = redirect_chain;
-    }
-  }
-
-  // Wrapper around NavigateAndCommit that also sets the redirect chain to
-  // a sane value.
-  void SimpleNavigateAndCommit(const GURL& url) {
-    std::vector<GURL> redirect_chain;
-    redirect_chain.push_back(url);
-    SetRedirectChain(redirect_chain, true);
-    NavigateAndCommit(url, GURL(), ui::PAGE_TRANSITION_LINK);
-  }
-
-  // This is similar to NavigateAndCommit that is in WebContentsTester, but
-  // allows us to specify the referrer and page_transition_type.
-  void NavigateAndCommit(const GURL& url,
-                         const GURL& referrer,
-                         ui::PageTransition type) {
-    auto navigation = content::NavigationSimulator::CreateBrowserInitiated(
-        url, web_contents());
-    navigation->SetReferrer(blink::mojom::Referrer::New(
-        referrer, network::mojom::ReferrerPolicy::kDefault));
-    navigation->SetTransition(type);
-    navigation->Commit();
-  }
-
-  RequestAndResult<ClientPhishingRequest> ExtractFeatures(
-      std::unique_ptr<ClientPhishingRequest> request) {
-    // Feature extraction takes ownership of the request object
-    // and passes it along to the done callback in the end.
-    uintptr_t key = StartExtractFeatures(std::move(request));
-    base::RunLoop().Run();
-    auto iterator = phishing_results_.find(key);
-    EXPECT_TRUE(iterator != phishing_results_.end());
-    if (iterator == phishing_results_.end())
-      return {};
-
-    auto result = std::move(iterator->second);
-    phishing_results_.erase(iterator);
-    return result;
-  }
-
-  uintptr_t StartExtractFeatures(
-      std::unique_ptr<ClientPhishingRequest> request) {
-    uintptr_t key = reinterpret_cast<uintptr_t>(request.get());
-    EXPECT_EQ(0u, phishing_results_.count(key));
-    ++num_pending_;
-    extractor_->ExtractFeatures(
-        browse_info_.get(), std::move(request),
-        base::BindOnce(&BrowserFeatureExtractorTest::ExtractFeaturesDone,
-                       base::Unretained(this)));
-    return key;
-  }
-
-  void GetFeatureMap(const ClientPhishingRequest& request,
-                     std::map<std::string, double>* features) {
-    for (int i = 0; i < request.non_model_feature_map_size(); ++i) {
-      const ClientPhishingRequest::Feature& feature =
-          request.non_model_feature_map(i);
-      EXPECT_EQ(0U, features->count(feature.name()));
-      (*features)[feature.name()] = feature.value();
-    }
-  }
-
-  int num_pending_;  // Number of pending feature extractions.
-  std::unique_ptr<BrowserFeatureExtractor> extractor_;
-  std::map<uintptr_t, RequestAndResult<ClientPhishingRequest>>
-      phishing_results_;
-  std::unique_ptr<BrowseInfo> browse_info_;
-  std::unique_ptr<StrictMock<MockClientSideDetectionHost>> host_;
-
- private:
-  void ExtractFeaturesDone(bool success,
-                           std::unique_ptr<ClientPhishingRequest> request) {
-    EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
-    uintptr_t key = reinterpret_cast<uintptr_t>(request.get());
-    ASSERT_EQ(0U, phishing_results_.count(key));
-    phishing_results_[key] = {std::move(request), success};
-    if (--num_pending_ == 0) {
-      base::RunLoop::QuitCurrentWhenIdleDeprecated();
-    }
-  }
-};
-
-TEST_F(BrowserFeatureExtractorTest, UrlNotInHistory) {
-  auto request = std::make_unique<ClientPhishingRequest>();
-  SimpleNavigateAndCommit(GURL("http://www.google.com"));
-  request->set_url("http://www.google.com/");
-  request->set_client_score(0.5);
-  EXPECT_FALSE(ExtractFeatures(std::move(request)).success);
-}
-
-TEST_F(BrowserFeatureExtractorTest, RequestNotInitialized) {
-  auto request = std::make_unique<ClientPhishingRequest>();
-  request->set_url("http://www.google.com/");
-  // Request is missing the score value.
-  SimpleNavigateAndCommit(GURL("http://www.google.com"));
-  EXPECT_FALSE(ExtractFeatures(std::move(request)).success);
-}
-
-TEST_F(BrowserFeatureExtractorTest, UrlInHistory) {
-  history_service()->AddPage(GURL("http://www.foo.com/bar.html"),
-                             base::Time::Now(),
-                             history::SOURCE_BROWSED);
-  history_service()->AddPage(GURL("https://www.foo.com/gaa.html"),
-                             base::Time::Now(),
-                             history::SOURCE_BROWSED);  // same host HTTPS.
-  history_service()->AddPage(GURL("http://www.foo.com/gaa.html"),
-                             base::Time::Now(),
-                             history::SOURCE_BROWSED);  // same host HTTP.
-  history_service()->AddPage(GURL("http://bar.foo.com/gaa.html"),
-                             base::Time::Now(),
-                             history::SOURCE_BROWSED);  // different host.
-  history_service()->AddPage(GURL("http://www.foo.com/bar.html?a=b"),
-                             base::Time::Now() - base::TimeDelta::FromHours(23),
-                             NULL, 0, GURL(), history::RedirectList(),
-                             ui::PAGE_TRANSITION_LINK, history::SOURCE_BROWSED,
-                             false, false);
-  history_service()->AddPage(GURL("http://www.foo.com/bar.html"),
-                             base::Time::Now() - base::TimeDelta::FromHours(25),
-                             NULL, 0, GURL(), history::RedirectList(),
-                             ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED,
-                             false, false);
-  history_service()->AddPage(GURL("https://www.foo.com/goo.html"),
-                             base::Time::Now() - base::TimeDelta::FromDays(5),
-                             NULL, 0, GURL(), history::RedirectList(),
-                             ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED,
-                             false, false);
-
-  SimpleNavigateAndCommit(GURL("http://www.foo.com/bar.html"));
-
-  {
-    auto request = std::make_unique<ClientPhishingRequest>();
-    request->set_url("http://www.foo.com/bar.html");
-    request->set_client_score(0.5);
-    auto result = ExtractFeatures(std::move(request));
-    EXPECT_TRUE(result.success);
-    ASSERT_TRUE(result.request);
-
-    std::map<std::string, double> features;
-    GetFeatureMap(*result.request, &features);
-
-    EXPECT_EQ(12U, features.size());
-    EXPECT_DOUBLE_EQ(2.0, features[kUrlHistoryVisitCount]);
-    EXPECT_DOUBLE_EQ(1.0, features[kUrlHistoryVisitCountMoreThan24hAgo]);
-    EXPECT_DOUBLE_EQ(1.0, features[kUrlHistoryTypedCount]);
-    EXPECT_DOUBLE_EQ(1.0, features[kUrlHistoryLinkCount]);
-    EXPECT_DOUBLE_EQ(4.0, features[kHttpHostVisitCount]);
-    EXPECT_DOUBLE_EQ(2.0, features[kHttpsHostVisitCount]);
-    EXPECT_DOUBLE_EQ(1.0, features[kFirstHttpHostVisitMoreThan24hAgo]);
-    EXPECT_DOUBLE_EQ(1.0, features[kFirstHttpsHostVisitMoreThan24hAgo]);
-  }
-
-  {
-    auto request = std::make_unique<ClientPhishingRequest>();
-    request->set_url("https://www.foo.com/gaa.html");
-    request->set_client_score(0.5);
-    auto result = ExtractFeatures(std::move(request));
-    EXPECT_TRUE(result.success);
-    EXPECT_TRUE(result.request);
-
-    std::map<std::string, double> features;
-    GetFeatureMap(*result.request, &features);
-
-    EXPECT_EQ(8U, features.size());
-    EXPECT_DOUBLE_EQ(1.0, features[kUrlHistoryVisitCount]);
-    EXPECT_DOUBLE_EQ(0.0, features[kUrlHistoryVisitCountMoreThan24hAgo]);
-    EXPECT_DOUBLE_EQ(0.0, features[kUrlHistoryTypedCount]);
-    EXPECT_DOUBLE_EQ(1.0, features[kUrlHistoryLinkCount]);
-    EXPECT_DOUBLE_EQ(4.0, features[kHttpHostVisitCount]);
-    EXPECT_DOUBLE_EQ(2.0, features[kHttpsHostVisitCount]);
-    EXPECT_DOUBLE_EQ(1.0, features[kFirstHttpHostVisitMoreThan24hAgo]);
-    EXPECT_DOUBLE_EQ(1.0, features[kFirstHttpsHostVisitMoreThan24hAgo]);
-  }
-
-  {
-    auto request = std::make_unique<ClientPhishingRequest>();
-    request->set_url("http://bar.foo.com/gaa.html");
-    request->set_client_score(0.5);
-    auto result = ExtractFeatures(std::move(request));
-    EXPECT_TRUE(result.success);
-    EXPECT_TRUE(result.request);
-
-    std::map<std::string, double> features;
-    GetFeatureMap(*result.request, &features);
-
-    // We have less features because we didn't Navigate to this page, so we
-    // don't have Referrer, IsFirstNavigation, HasSSLReferrer, etc.
-    EXPECT_EQ(7U, features.size());
-    EXPECT_DOUBLE_EQ(1.0, features[kUrlHistoryVisitCount]);
-    EXPECT_DOUBLE_EQ(0.0, features[kUrlHistoryVisitCountMoreThan24hAgo]);
-    EXPECT_DOUBLE_EQ(0.0, features[kUrlHistoryTypedCount]);
-    EXPECT_DOUBLE_EQ(1.0, features[kUrlHistoryLinkCount]);
-    EXPECT_DOUBLE_EQ(1.0, features[kHttpHostVisitCount]);
-    EXPECT_DOUBLE_EQ(0.0, features[kHttpsHostVisitCount]);
-    EXPECT_DOUBLE_EQ(0.0, features[kFirstHttpHostVisitMoreThan24hAgo]);
-    EXPECT_FALSE(features.count(kFirstHttpsHostVisitMoreThan24hAgo));
-  }
-}
-
-TEST_F(BrowserFeatureExtractorTest, MultipleRequestsAtOnce) {
-  history_service()->AddPage(GURL("http://www.foo.com/bar.html"),
-                             base::Time::Now(),
-                             history::SOURCE_BROWSED);
-  SimpleNavigateAndCommit(GURL("http:/www.foo.com/bar.html"));
-  auto request1 = std::make_unique<ClientPhishingRequest>();
-  request1->set_url("http://www.foo.com/bar.html");
-  request1->set_client_score(0.5);
-  uintptr_t key1 = StartExtractFeatures(std::move(request1));
-
-  SimpleNavigateAndCommit(GURL("http://www.foo.com/goo.html"));
-  auto request2 = std::make_unique<ClientPhishingRequest>();
-  request2->set_url("http://www.foo.com/goo.html");
-  request2->set_client_score(1.0);
-  uintptr_t key2 = StartExtractFeatures(std::move(request2));
-
-  base::RunLoop().Run();
-  EXPECT_TRUE(phishing_results_[key1].success);
-  // Success is false because the second URL is not in the history and we are
-  // not able to distinguish between a missing URL in the history and an error.
-  EXPECT_FALSE(phishing_results_[key2].success);
-}
-
-TEST_F(BrowserFeatureExtractorTest, BrowseFeatures) {
-  history_service()->AddPage(GURL("http://www.foo.com/"),
-                             base::Time::Now(),
-                             history::SOURCE_BROWSED);
-  history_service()->AddPage(GURL("http://www.foo.com/page.html"),
-                             base::Time::Now(),
-                             history::SOURCE_BROWSED);
-  history_service()->AddPage(GURL("http://www.bar.com/"),
-                             base::Time::Now(),
-                             history::SOURCE_BROWSED);
-  history_service()->AddPage(GURL("http://www.bar.com/other_page.html"),
-                             base::Time::Now(),
-                             history::SOURCE_BROWSED);
-  history_service()->AddPage(GURL("http://www.baz.com/"),
-                             base::Time::Now(),
-                             history::SOURCE_BROWSED);
-
-  {
-    auto request = std::make_unique<ClientPhishingRequest>();
-    request->set_url("http://www.foo.com/");
-    request->set_client_score(0.5);
-    std::vector<GURL> redirect_chain;
-    redirect_chain.push_back(GURL("http://somerandomwebsite.com/"));
-    redirect_chain.push_back(GURL("http://www.foo.com/"));
-    SetRedirectChain(redirect_chain, true);
-    browse_info_->http_status_code = 200;
-    NavigateAndCommit(
-        GURL("http://www.foo.com/"), GURL("http://google.com/"),
-        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_AUTO_BOOKMARK |
-                                  ui::PAGE_TRANSITION_FORWARD_BACK));
-
-    auto result = ExtractFeatures(std::move(request));
-    EXPECT_TRUE(result.success);
-    ASSERT_TRUE(result.request);
-
-    std::map<std::string, double> features;
-    GetFeatureMap(*result.request, &features);
-
-    EXPECT_EQ(
-        1.0,
-        features[base::StringPrintf("%s=%s", kReferrer, "http://google.com/")]);
-    EXPECT_EQ(1.0,
-              features[base::StringPrintf("%s[0]=%s", kRedirect,
-                                          "http://somerandomwebsite.com/")]);
-    // We shouldn't have a feature for the last redirect in the chain, since it
-    // should always be the URL that we navigated to.
-    EXPECT_EQ(
-        0.0,
-        features[base::StringPrintf("%s[1]=%s", kRedirect, "http://foo.com/")]);
-    EXPECT_EQ(0.0, features[kHasSSLReferrer]);
-    EXPECT_EQ(2.0, features[kPageTransitionType]);
-    EXPECT_EQ(1.0, features[kIsFirstNavigation]);
-    EXPECT_EQ(200.0, features[kHttpStatusCode]);
-  }
-
-  {
-    auto request = std::make_unique<ClientPhishingRequest>();
-    request->set_url("http://www.foo.com/page.html");
-    request->set_client_score(0.5);
-    std::vector<GURL> redirect_chain;
-    redirect_chain.push_back(GURL("http://www.foo.com/redirect"));
-    redirect_chain.push_back(GURL("http://www.foo.com/second_redirect"));
-    redirect_chain.push_back(GURL("http://www.foo.com/page.html"));
-    SetRedirectChain(redirect_chain, false);
-    browse_info_->http_status_code = 404;
-    NavigateAndCommit(
-        GURL("http://www.foo.com/page.html"), GURL("http://www.foo.com"),
-        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
-                                  ui::PAGE_TRANSITION_CHAIN_START |
-                                  ui::PAGE_TRANSITION_CLIENT_REDIRECT));
-
-    auto result = ExtractFeatures(std::move(request));
-    EXPECT_TRUE(result.success);
-    ASSERT_TRUE(result.request);
-
-    std::map<std::string, double> features;
-    GetFeatureMap(*result.request, &features);
-
-    EXPECT_EQ(1, features[base::StringPrintf("%s=%s", kReferrer,
-                                             "http://www.foo.com/")]);
-    EXPECT_EQ(1.0, features[base::StringPrintf("%s[0]=%s", kRedirect,
-                                               "http://www.foo.com/redirect")]);
-    EXPECT_EQ(
-        1.0, features[base::StringPrintf(
-                 "%s[1]=%s", kRedirect, "http://www.foo.com/second_redirect")]);
-    EXPECT_EQ(0.0, features[kHasSSLReferrer]);
-    EXPECT_EQ(1.0, features[kPageTransitionType]);
-    EXPECT_EQ(0.0, features[kIsFirstNavigation]);
-    EXPECT_EQ(1.0,
-              features[base::StringPrintf("%s%s=%s", kHostPrefix, kReferrer,
-                                          "http://google.com/")]);
-    EXPECT_EQ(1.0,
-              features[base::StringPrintf("%s%s[0]=%s", kHostPrefix, kRedirect,
-                                          "http://somerandomwebsite.com/")]);
-    EXPECT_EQ(
-        2.0,
-        features[base::StringPrintf("%s%s", kHostPrefix, kPageTransitionType)]);
-    EXPECT_EQ(
-        1.0,
-        features[base::StringPrintf("%s%s", kHostPrefix, kIsFirstNavigation)]);
-    EXPECT_EQ(404.0, features[kHttpStatusCode]);
-  }
-
-  {
-    auto request = std::make_unique<ClientPhishingRequest>();
-    request->set_url("http://www.bar.com/");
-    request->set_client_score(0.5);
-    std::vector<GURL> redirect_chain;
-    redirect_chain.push_back(GURL("http://www.foo.com/page.html"));
-    redirect_chain.push_back(GURL("http://www.bar.com/"));
-    SetRedirectChain(redirect_chain, true);
-    NavigateAndCommit(
-        GURL("http://www.bar.com/"), GURL("http://www.foo.com/page.html"),
-        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
-                                  ui::PAGE_TRANSITION_CHAIN_END |
-                                  ui::PAGE_TRANSITION_CLIENT_REDIRECT));
-
-    auto result = ExtractFeatures(std::move(request));
-    EXPECT_TRUE(result.success);
-    ASSERT_TRUE(result.request);
-
-    std::map<std::string, double> features;
-    GetFeatureMap(*result.request, &features);
-
-    EXPECT_EQ(1.0, features[base::StringPrintf(
-                       "%s=%s", kReferrer, "http://www.foo.com/page.html")]);
-    EXPECT_EQ(1.0, features[base::StringPrintf(
-                       "%s[0]=%s", kRedirect, "http://www.foo.com/page.html")]);
-    EXPECT_EQ(0.0, features[kHasSSLReferrer]);
-    EXPECT_EQ(0.0, features[kPageTransitionType]);
-    EXPECT_EQ(0.0, features[kIsFirstNavigation]);
-
-    // Should not have host features.
-    EXPECT_EQ(0U, features.count(base::StringPrintf("%s%s", kHostPrefix,
-                                                    kPageTransitionType)));
-    EXPECT_EQ(0U, features.count(base::StringPrintf("%s%s", kHostPrefix,
-                                                    kIsFirstNavigation)));
-  }
-
-  {
-    auto request = std::make_unique<ClientPhishingRequest>();
-    request->set_url("http://www.bar.com/other_page.html");
-    request->set_client_score(0.5);
-    std::vector<GURL> redirect_chain;
-    redirect_chain.push_back(GURL("http://www.bar.com/other_page.html"));
-    SetRedirectChain(redirect_chain, false);
-    NavigateAndCommit(GURL("http://www.bar.com/other_page.html"),
-                      GURL("http://www.bar.com/"), ui::PAGE_TRANSITION_LINK);
-
-    auto result = ExtractFeatures(std::move(request));
-    EXPECT_TRUE(result.success);
-    ASSERT_TRUE(result.request);
-
-    std::map<std::string, double> features;
-    GetFeatureMap(*result.request, &features);
-
-    EXPECT_EQ(1.0, features[base::StringPrintf("%s=%s", kReferrer,
-                                               "http://www.bar.com/")]);
-    EXPECT_EQ(0.0, features[kHasSSLReferrer]);
-    EXPECT_EQ(0.0, features[kPageTransitionType]);
-    EXPECT_EQ(0.0, features[kIsFirstNavigation]);
-    EXPECT_EQ(1.0,
-              features[base::StringPrintf("%s%s=%s", kHostPrefix, kReferrer,
-                                          "http://www.foo.com/page.html")]);
-    EXPECT_EQ(1.0,
-              features[base::StringPrintf("%s%s[0]=%s", kHostPrefix, kRedirect,
-                                          "http://www.foo.com/page.html")]);
-    EXPECT_EQ(
-        0.0,
-        features[base::StringPrintf("%s%s", kHostPrefix, kPageTransitionType)]);
-    EXPECT_EQ(
-        0.0,
-        features[base::StringPrintf("%s%s", kHostPrefix, kIsFirstNavigation)]);
-  }
-
-  {
-    auto request = std::make_unique<ClientPhishingRequest>();
-    request->set_url("http://www.baz.com/");
-    request->set_client_score(0.5);
-    std::vector<GURL> redirect_chain;
-    redirect_chain.push_back(GURL("https://bankofamerica.com"));
-    redirect_chain.push_back(GURL("http://www.baz.com/"));
-    SetRedirectChain(redirect_chain, true);
-    NavigateAndCommit(GURL("http://www.baz.com"),
-                      GURL("https://bankofamerica.com"),
-                      ui::PAGE_TRANSITION_GENERATED);
-
-    auto result = ExtractFeatures(std::move(request));
-    EXPECT_TRUE(result.success);
-    ASSERT_TRUE(result.request);
-
-    std::map<std::string, double> features;
-    GetFeatureMap(*result.request, &features);
-
-    EXPECT_EQ(1.0, features[base::StringPrintf("%s[0]=%s", kRedirect,
-                                               kSecureRedirectValue)]);
-    EXPECT_EQ(1.0, features[kHasSSLReferrer]);
-    EXPECT_EQ(5.0, features[kPageTransitionType]);
-    // Should not have redirect or host features.
-    EXPECT_EQ(0U, features.count(base::StringPrintf("%s%s", kHostPrefix,
-                                                    kPageTransitionType)));
-    EXPECT_EQ(0U, features.count(base::StringPrintf("%s%s", kHostPrefix,
-                                                    kIsFirstNavigation)));
-    EXPECT_EQ(5.0, features[kPageTransitionType]);
-  }
-}
-
-TEST_F(BrowserFeatureExtractorTest, SafeBrowsingFeatures) {
-  SimpleNavigateAndCommit(GURL("http://www.foo.com/malware.html"));
-  auto request = std::make_unique<ClientPhishingRequest>();
-  request->set_url("http://www.foo.com/malware.html");
-  request->set_client_score(0.5);
-
-  browse_info_->unsafe_resource.reset(
-      new security_interstitials::UnsafeResource);
-  browse_info_->unsafe_resource->url = GURL("http://www.malware.com/");
-  browse_info_->unsafe_resource->original_url = GURL("http://www.good.com/");
-  browse_info_->unsafe_resource->is_subresource = true;
-  browse_info_->unsafe_resource->threat_type = SB_THREAT_TYPE_URL_MALWARE;
-
-  auto result = ExtractFeatures(std::move(request));
-  ASSERT_TRUE(result.request);
-
-  std::map<std::string, double> features;
-  GetFeatureMap(*result.request, &features);
-  EXPECT_TRUE(features.count(base::StringPrintf(
-      "%s%s", kSafeBrowsingMaliciousUrl, "http://www.malware.com/")));
-  EXPECT_TRUE(features.count(base::StringPrintf(
-      "%s%s", kSafeBrowsingOriginalUrl, "http://www.good.com/")));
-  EXPECT_DOUBLE_EQ(1.0, features[kSafeBrowsingIsSubresource]);
-  EXPECT_DOUBLE_EQ(SB_THREAT_TYPE_URL_MALWARE,
-                   features[kSafeBrowsingThreatType]);
-}
-
-}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/browser_features.cc b/chrome/browser/safe_browsing/browser_features.cc
deleted file mode 100644
index bb5554c..0000000
--- a/chrome/browser/safe_browsing/browser_features.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2011 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/safe_browsing/browser_features.h"
-
-namespace safe_browsing {
-const char kUrlHistoryVisitCount[] = "UrlHistoryVisitCount";
-const char kUrlHistoryTypedCount[] = "UrlHistoryTypedCount";
-const char kUrlHistoryLinkCount[] = "UrlHistoryLinkCount";
-const char kUrlHistoryVisitCountMoreThan24hAgo[] =
-    "UrlHistoryVisitCountMoreThan24hAgo";
-const char kHttpHostVisitCount[] = "HttpHostVisitCount";
-const char kHttpsHostVisitCount[] = "HttpsHostVisitCount";
-const char kFirstHttpHostVisitMoreThan24hAgo[] =
-    "FirstHttpHostVisitMoreThan24hAgo";
-const char kFirstHttpsHostVisitMoreThan24hAgo[] =
-    "FirstHttpsHostVisitMoreThan24hAgo";
-
-const char kHostPrefix[] = "Host";
-const char kReferrer[] = "Referrer";
-const char kHasSSLReferrer[] = "HasSSLReferrer";
-const char kPageTransitionType[] = "PageTransitionType";
-const char kIsFirstNavigation[] = "IsFirstNavigation";
-const char kRedirectUrlMismatch[] = "RedirectUrlMismatch";
-const char kRedirect[] = "Redirect";
-const char kSecureRedirectValue[] = "SecureRedirect";
-const char kHttpStatusCode[] = "HttpStatusCode";
-const char kSafeBrowsingMaliciousUrl[] = "SafeBrowsingMaliciousUrl=";
-const char kSafeBrowsingOriginalUrl[] = "SafeBrowsingOriginalUrl=";
-const char kSafeBrowsingIsSubresource[] = "SafeBrowsingIsSubresource";
-const char kSafeBrowsingThreatType[] = "SafeBrowsingThreatType";
-}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/browser_features.h b/chrome/browser/safe_browsing/browser_features.h
deleted file mode 100644
index 91855cb..0000000
--- a/chrome/browser/safe_browsing/browser_features.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (c) 2011 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.
-//
-// Client-side phishing features that are extracted by the browser, after
-// receiving a score from the renderer.
-
-#ifndef CHROME_BROWSER_SAFE_BROWSING_BROWSER_FEATURES_H_
-#define CHROME_BROWSER_SAFE_BROWSING_BROWSER_FEATURES_H_
-
-namespace safe_browsing {
-
-// IMPORTANT: when adding new features, you must update kAllowedFeatures in
-// chrome/browser/safe_browsing/client_side_detection_service.cc if the feature
-// should be sent in sanitized pingbacks.
-//
-////////////////////////////////////////////////////
-// History features.
-////////////////////////////////////////////////////
-
-// Number of visits to that URL stored in the browser history.
-// Should always be an integer larger than 1 because by the time
-// we lookup the history the current URL should already be stored there.
-extern const char kUrlHistoryVisitCount[];
-
-// Number of times the URL was typed in the Omnibox.
-extern const char kUrlHistoryTypedCount[];
-
-// Number of times the URL was reached by clicking a link.
-extern const char kUrlHistoryLinkCount[];
-
-// Number of times URL was visited more than 24h ago.
-extern const char kUrlHistoryVisitCountMoreThan24hAgo[];
-
-// Number of user-visible visits to all URLs on the same host/port as
-// the URL for HTTP and HTTPs.
-extern const char kHttpHostVisitCount[];
-extern const char kHttpsHostVisitCount[];
-
-// Boolean feature which is true if the host was visited for the first
-// time more than 24h ago (only considers user-visible visits like above).
-extern const char kFirstHttpHostVisitMoreThan24hAgo[];
-extern const char kFirstHttpsHostVisitMoreThan24hAgo[];
-
-////////////////////////////////////////////////////
-// Browse features.
-////////////////////////////////////////////////////
-// Note that these features may have the following prefixes appended to them
-// that tell for which page type the feature pertains.
-extern const char kHostPrefix[];
-
-// Referrer
-extern const char kReferrer[];
-// True if the referrer was stripped because it is an SSL referrer.
-extern const char kHasSSLReferrer[];
-// Stores the page transition.  See: PageTransition.  We strip the qualifier.
-extern const char kPageTransitionType[];
-// True if this navigation is the first for this tab.
-extern const char kIsFirstNavigation[];
-// Feature that is set if the url from the navigation entry doesn't match the
-// url at the end of the redirect chain.
-extern const char kRedirectUrlMismatch[];
-// The redirect chain that leads to the named page.
-extern const char kRedirect[];
-// If a redirect is SSL, we will use this value instead of the actual redirect
-// so we don't leak any SSL sites.
-extern const char kSecureRedirectValue[];
-
-// The HTTP status code for the main document.
-extern const char kHttpStatusCode[];
-
-// SafeBrowsing related featues.  Fields from the UnsafeResource if there is
-// any.
-extern const char kSafeBrowsingMaliciousUrl[];
-extern const char kSafeBrowsingOriginalUrl[];
-extern const char kSafeBrowsingIsSubresource[];
-extern const char kSafeBrowsingThreatType[];
-}  // namespace safe_browsing
-
-#endif  // CHROME_BROWSER_SAFE_BROWSING_BROWSER_FEATURES_H_
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.cc b/chrome/browser/safe_browsing/client_side_detection_host.cc
index 6699c67..beec4237 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host.cc
@@ -21,7 +21,6 @@
 #include "base/time/tick_clock.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/safe_browsing/browser_feature_extractor.h"
 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
 #include "chrome/browser/safe_browsing/client_side_detection_service_factory.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
@@ -35,7 +34,6 @@
 #include "components/safe_browsing/core/db/database_manager.h"
 #include "components/safe_browsing/core/proto/csd.pb.h"
 #include "components/security_interstitials/content/unsafe_resource_util.h"
-#include "components/security_interstitials/core/unsafe_resource.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_controller.h"
@@ -308,27 +306,21 @@
       tab_(tab),
       classification_request_(nullptr),
       pageload_complete_(false),
-      unsafe_unique_page_id_(-1),
       tick_clock_(base::DefaultTickClock::GetInstance()) {
   DCHECK(tab);
   // Note: csd_service_ and sb_service will be nullptr here in testing.
   csd_service_ = ClientSideDetectionServiceFactory::GetForProfile(
       Profile::FromBrowserContext(tab->GetBrowserContext()));
-  feature_extractor_.reset(new BrowserFeatureExtractor(tab));
 
   scoped_refptr<SafeBrowsingService> sb_service =
       g_browser_process->safe_browsing_service();
   if (sb_service.get()) {
     ui_manager_ = sb_service->ui_manager();
     database_manager_ = sb_service->database_manager();
-    ui_manager_->AddObserver(this);
   }
 }
 
 ClientSideDetectionHost::~ClientSideDetectionHost() {
-  if (ui_manager_.get())
-    ui_manager_->RemoveObserver(this);
-
   if (csd_service_)
     csd_service_->RemoveClientSideDetectionHost(this);
 }
@@ -361,21 +353,8 @@
   if (!csd_service_) {
     return;
   }
-  browse_info_.reset(new BrowseInfo);
 
-  // Store redirect chain information.
-  if (navigation_handle->GetURL().host() != cur_host_) {
-    cur_host_ = navigation_handle->GetURL().host();
-    cur_host_redirects_ = navigation_handle->GetRedirectChain();
-  }
-  browse_info_->url = navigation_handle->GetURL();
-  browse_info_->host_redirects = cur_host_redirects_;
-  browse_info_->url_redirects = navigation_handle->GetRedirectChain();
-  browse_info_->referrer = navigation_handle->GetReferrer().url;
-  if (navigation_handle->GetResponseHeaders()) {
-    browse_info_->http_status_code =
-        navigation_handle->GetResponseHeaders()->response_code();
-  }
+  current_url_ = navigation_handle->GetURL();
 
   pageload_complete_ = false;
 
@@ -402,40 +381,11 @@
   }
 }
 
-void ClientSideDetectionHost::OnSafeBrowsingHit(
-    const security_interstitials::UnsafeResource& resource) {
-  if (!web_contents())
-    return;
-
-  // Check that the hit is either malware or phishing.
-  if (resource.threat_type != SB_THREAT_TYPE_URL_PHISHING &&
-      resource.threat_type != SB_THREAT_TYPE_URL_MALWARE)
-    return;
-
-  // Check that this notification is really for us.
-  if (web_contents() != resource.web_contents_getter.Run())
-    return;
-
-  NavigationEntry* entry = GetNavigationEntryForResource(resource);
-  if (!entry)
-    return;
-
-  // Store the unique page ID for later.
-  unsafe_unique_page_id_ = entry->GetUniqueID();
-
-  // We also keep the resource around in order to be able to send the
-  // malicious URL to the server.
-  unsafe_resource_.reset(new security_interstitials::UnsafeResource(resource));
-  unsafe_resource_->callback.Reset();  // Don't do anything stupid.
-}
-
 void ClientSideDetectionHost::WebContentsDestroyed() {
   // Tell any pending classification request that it is being canceled.
   if (classification_request_.get()) {
     classification_request_->Cancel();
   }
-  // Cancel all pending feature extractions.
-  feature_extractor_.reset();
   if (csd_service_)
     csd_service_->RemoveClientSideDetectionHost(this);
 }
@@ -452,14 +402,14 @@
 void ClientSideDetectionHost::OnPhishingPreClassificationDone(
     bool should_classify) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (browse_info_.get() && should_classify) {
+  if (should_classify) {
     content::RenderFrameHost* rfh = web_contents()->GetMainFrame();
     phishing_detector_.reset();
     rfh->GetRemoteInterfaces()->GetInterface(
         phishing_detector_.BindNewPipeAndPassReceiver());
     phishing_detection_start_time_ = tick_clock_->NowTicks();
     phishing_detector_->StartPhishingDetection(
-        browse_info_->url,
+        current_url_,
         base::BindOnce(&ClientSideDetectionHost::PhishingDetectionDone,
                        weak_factory_.GetWeakPtr()));
   }
@@ -473,7 +423,6 @@
   // this method is called.  The renderer should not start phishing detection
   // if there isn't any service class in the browser.
   DCHECK(csd_service_);
-  DCHECK(browse_info_.get());
 
   UmaHistogramMediumTimes(
       "SBClientPhishing.PhishingDetectionDuration",
@@ -491,7 +440,6 @@
   // send the verdict further.
   std::unique_ptr<ClientPhishingRequest> verdict(new ClientPhishingRequest);
   if (csd_service_ &&
-      browse_info_.get() &&
       verdict->ParseFromString(verdict_str) &&
       verdict->IsInitialized()) {
     VLOG(2) << "Phishing classification score: " << verdict->client_score();
@@ -510,15 +458,15 @@
 
     // We only send phishing verdict to the server if the verdict is phishing.
     if (verdict->is_phishing()) {
-      if (DidShowSBInterstitial()) {
-        browse_info_->unsafe_resource = std::move(unsafe_resource_);
-      }
-      // Start browser-side feature extraction.  Once we're done it will send
-      // the client verdict request.
-      feature_extractor_->ExtractFeatures(
-          browse_info_.get(), std::move(verdict),
-          base::BindOnce(&ClientSideDetectionHost::FeatureExtractionDone,
-                         weak_factory_.GetWeakPtr()));
+      ClientSideDetectionService::ClientReportPhishingRequestCallback callback =
+          base::Bind(&ClientSideDetectionHost::MaybeShowPhishingWarning,
+                     weak_factory_.GetWeakPtr(),
+                     /*is_from_cache=*/false);
+      Profile* profile =
+          Profile::FromBrowserContext(web_contents()->GetBrowserContext());
+      csd_service_->SendClientReportPhishingRequest(
+          std::move(verdict), IsExtendedReportingEnabled(*profile->GetPrefs()),
+          IsEnhancedProtectionEnabled(*profile->GetPrefs()), callback);
     }
   }
 }
@@ -562,40 +510,6 @@
   }
 }
 
-void ClientSideDetectionHost::FeatureExtractionDone(
-    bool success,
-    std::unique_ptr<ClientPhishingRequest> request) {
-  DCHECK(request);
-  ClientSideDetectionService::ClientReportPhishingRequestCallback callback;
-  // If the client-side verdict isn't phishing we don't care about the server
-  // response because we aren't going to display a warning.
-  if (request->is_phishing()) {
-    callback = base::Bind(&ClientSideDetectionHost::MaybeShowPhishingWarning,
-                          weak_factory_.GetWeakPtr(), /*is_from_cache=*/false);
-  }
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
-  // Send ping even if the browser feature extraction failed.
-  csd_service_->SendClientReportPhishingRequest(
-      std::move(request), IsExtendedReportingEnabled(*profile->GetPrefs()),
-      IsEnhancedProtectionEnabled(*profile->GetPrefs()), callback);
-}
-
-bool ClientSideDetectionHost::DidShowSBInterstitial() const {
-  if (unsafe_unique_page_id_ <= 0 || !web_contents()) {
-    return false;
-  }
-  // DidShowSBInterstitial is called after client side detection is finished to
-  // see if a SB interstitial was shown on the same page. Client Side Detection
-  // only runs on the currently committed page, so an unconditional
-  // GetLastCommittedEntry is correct here. GetNavigationEntryForResource cannot
-  // be used since it may no longer be valid (eg, if the UnsafeResource was for
-  // a blocking main page load which was then proceeded through).
-  NavigationEntry* nav_entry =
-      web_contents()->GetController().GetLastCommittedEntry();
-  return (nav_entry && nav_entry->GetUniqueID() == unsafe_unique_page_id_);
-}
-
 void ClientSideDetectionHost::set_client_side_detection_service(
     ClientSideDetectionService* service) {
   csd_service_ = service;
@@ -603,12 +517,7 @@
 
 void ClientSideDetectionHost::set_ui_manager(
     SafeBrowsingUIManager* ui_manager) {
-  if (ui_manager_.get())
-    ui_manager_->RemoveObserver(this);
-
   ui_manager_ = ui_manager;
-  if (ui_manager)
-    ui_manager_->AddObserver(this);
 }
 
 void ClientSideDetectionHost::set_database_manager(
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.h b/chrome/browser/safe_browsing/client_side_detection_host.h
index 1ea5e02a..e94704a 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host.h
+++ b/chrome/browser/safe_browsing/client_side_detection_host.h
@@ -13,7 +13,6 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "chrome/browser/safe_browsing/browser_feature_extractor.h"
 #include "chrome/browser/safe_browsing/client_side_model_loader.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
 #include "components/safe_browsing/content/common/safe_browsing.mojom-shared.h"
@@ -37,8 +36,7 @@
 // class relays this information to the client-side detection service
 // class which sends a ping to a server to validate the verdict.
 // TODO(noelutz): move all client-side detection IPCs to this class.
-class ClientSideDetectionHost : public content::WebContentsObserver,
-                                public SafeBrowsingUIManager::Observer {
+class ClientSideDetectionHost : public content::WebContentsObserver {
  public:
   // The caller keeps ownership of the tab object and is responsible for
   // ensuring that it stays valid until WebContentsDestroyed is called.
@@ -55,13 +53,6 @@
   // Send the model to all the render frame hosts in this WebContents.
   void SendModelToRenderFrame();
 
-  // Called when the SafeBrowsingService found a hit with one of the
-  // SafeBrowsing lists.  This method is called on the UI thread.
-  void OnSafeBrowsingHit(
-      const security_interstitials::UnsafeResource& resource) override;
-
-  BrowseInfo* GetBrowseInfo() const { return browse_info_.get(); }
-
  protected:
   explicit ClientSideDetectionHost(content::WebContents* tab);
 
@@ -98,12 +89,6 @@
                                 GURL phishing_url,
                                 bool is_phishing);
 
-  // Callback that is called when the browser feature extractor is done.
-  // This method is responsible for deleting the request object.  Called on
-  // the UI thread.
-  void FeatureExtractionDone(bool success,
-                             std::unique_ptr<ClientPhishingRequest> request);
-
   // Returns true if the user has seen a regular SafeBrowsing
   // interstitial for the current page.  This is only true if the user has
   // actually clicked through the warning.  This method is called on the UI
@@ -129,16 +114,8 @@
   // Keep a handle to the latest classification request so that we can cancel
   // it if necessary.
   scoped_refptr<ShouldClassifyUrlRequest> classification_request_;
-  // Browser-side feature extractor.
-  std::unique_ptr<BrowserFeatureExtractor> feature_extractor_;
-  // Keeps some info about the current page visit while the renderer
-  // classification is going on.  Since we cancel classification on
-  // every page load we can simply keep this data around as a member
-  // variable.  This information will be passed on to the feature extractor.
-  std::unique_ptr<BrowseInfo> browse_info_;
-  // Redirect chain that leads to the first page of the current host. We keep
-  // track of this for browse_info_.
-  std::vector<GURL> cur_host_redirects_;
+  // The current URL
+  GURL current_url_;
   // Current host, used to help determine cur_host_redirects_.
   std::string cur_host_;
   // The currently active message pipe to the renderer PhishingDetector.
@@ -148,11 +125,6 @@
   static const size_t kMaxIPsPerBrowse;
   bool pageload_complete_;
 
-  // Unique page ID of the most recent unsafe site that was loaded in this tab
-  // as well as the UnsafeResource.
-  int unsafe_unique_page_id_;
-  std::unique_ptr<security_interstitials::UnsafeResource> unsafe_resource_;
-
   // Records the start time of when phishing detection started.
   base::TimeTicks phishing_detection_start_time_;
   const base::TickClock* tick_clock_;
diff --git a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
index a698e6fb..8b59881 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
@@ -18,7 +18,6 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/simple_test_tick_clock.h"
-#include "chrome/browser/safe_browsing/browser_feature_extractor.h"
 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
 #include "chrome/browser/safe_browsing/client_side_model_loader.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
@@ -176,18 +175,6 @@
   DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager);
 };
 
-class MockBrowserFeatureExtractor : public BrowserFeatureExtractor {
- public:
-  explicit MockBrowserFeatureExtractor(WebContents* tab)
-      : BrowserFeatureExtractor(tab) {}
-  ~MockBrowserFeatureExtractor() override {}
-
-  MOCK_METHOD3(ExtractFeatures,
-               void(const BrowseInfo*,
-                    std::unique_ptr<ClientPhishingRequest>,
-                    BrowserFeatureExtractor::DoneCallback));
-};
-
 }  // namespace
 
 class FakePhishingDetector : public mojom::PhishingDetector {
@@ -292,10 +279,6 @@
     csd_host_->set_ui_manager(ui_manager_.get());
     csd_host_->set_database_manager(database_manager_.get());
     csd_host_->set_tick_clock_for_testing(&clock_);
-
-    // We need to create this here since we don't call DidStopLanding in
-    // this test.
-    csd_host_->browse_info_.reset(new BrowseInfo);
   }
 
   void TearDown() override {
@@ -356,84 +339,12 @@
     EXPECT_TRUE(Mock::VerifyAndClear(database_manager_.get()));
   }
 
-  void SetFeatureExtractor(BrowserFeatureExtractor* extractor) {
-    csd_host_->feature_extractor_.reset(extractor);
-  }
-
-  void SetRedirectChain(const std::vector<GURL>& redirect_chain) {
-    csd_host_->browse_info_->url_redirects = redirect_chain;
-  }
-
-  void TestUnsafeResourceCopied(const UnsafeResource& resource) {
-    ASSERT_TRUE(csd_host_->unsafe_resource_.get());
-    // Test that the resource from OnSafeBrowsingHit notification was copied
-    // into the CSDH.
-    EXPECT_EQ(resource.url, csd_host_->unsafe_resource_->url);
-    EXPECT_EQ(resource.original_url, csd_host_->unsafe_resource_->original_url);
-    EXPECT_EQ(resource.is_subresource,
-              csd_host_->unsafe_resource_->is_subresource);
-    EXPECT_EQ(resource.threat_type, csd_host_->unsafe_resource_->threat_type);
-    EXPECT_TRUE(csd_host_->unsafe_resource_->callback.is_null());
-    EXPECT_EQ(resource.web_contents_getter.Run(),
-              csd_host_->unsafe_resource_->web_contents_getter.Run());
-  }
-
-  void SetUnsafeSubResourceForCurrent(bool expect_unsafe_resource) {
-    UnsafeResource resource;
-    resource.url = GURL("http://www.malware.com/");
-    resource.original_url = web_contents()->GetURL();
-    resource.is_subresource = true;
-    resource.threat_type = SB_THREAT_TYPE_URL_MALWARE;
-    resource.callback = base::DoNothing();
-    resource.callback_thread = content::GetIOThreadTaskRunner({});
-    resource.web_contents_getter = security_interstitials::GetWebContentsGetter(
-        web_contents()->GetMainFrame()->GetProcess()->GetID(),
-        web_contents()->GetMainFrame()->GetRoutingID());
-    csd_host_->OnSafeBrowsingHit(resource);
-    resource.callback.Reset();
-    ASSERT_EQ(expect_unsafe_resource, csd_host_->DidShowSBInterstitial());
-    if (expect_unsafe_resource)
-      TestUnsafeResourceCopied(resource);
-  }
-
-  void NavigateWithSBHitAndCommit(const GURL& url) {
-    // Create a pending navigation.
-    controller().LoadURL(
-        url, content::Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
-
-    ASSERT_TRUE(pending_main_rfh());
-
-    // Simulate a safebrowsing hit before navigation completes.
-    UnsafeResource resource;
-    resource.url = url;
-    resource.original_url = url;
-    resource.is_subresource = false;
-    resource.threat_type = SB_THREAT_TYPE_URL_MALWARE;
-    resource.callback = base::DoNothing();
-    resource.callback_thread = content::GetIOThreadTaskRunner({});
-    resource.web_contents_getter = security_interstitials::GetWebContentsGetter(
-        pending_rvh()->GetProcess()->GetID(),
-        pending_main_rfh()->GetRoutingID());
-    csd_host_->OnSafeBrowsingHit(resource);
-    resource.callback.Reset();
-
-    // LoadURL created a navigation entry, now simulate the RenderView sending
-    // a notification that it actually navigated.
-    content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
-
-    ASSERT_TRUE(csd_host_->DidShowSBInterstitial());
-    TestUnsafeResourceCopied(resource);
-  }
-
-  void NavigateWithoutSBHitAndCommit(const GURL& safe_url) {
+  void NavigateAndCommit(const GURL& safe_url) {
     controller().LoadURL(
         safe_url, content::Referrer(), ui::PAGE_TRANSITION_LINK,
         std::string());
 
-    ASSERT_TRUE(pending_main_rfh());
-
     content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
-    ASSERT_FALSE(csd_host_->DidShowSBInterstitial());
   }
 
   void AdvanceTimeTickClock(base::TimeDelta delta) { clock_.Advance(delta); }
@@ -464,35 +375,21 @@
 TEST_F(ClientSideDetectionHostTest, PhishingDetectionDoneInvalidVerdict) {
   // Case 0: renderer sends an invalid verdict string that we're unable to
   // parse.
-  MockBrowserFeatureExtractor* mock_extractor =
-      new StrictMock<MockBrowserFeatureExtractor>(web_contents());
-  SetFeatureExtractor(mock_extractor);  // The host class takes ownership.
-  EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
+  EXPECT_CALL(*csd_service_, SendClientReportPhishingRequest(_, _, _, _))
+      .Times(0);
   PhishingDetectionDone("Invalid Protocol Buffer");
-  EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
+  EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
 }
 
 TEST_F(ClientSideDetectionHostTest, PhishingDetectionDoneNotPhishing) {
   // Case 1: client thinks the page is phishing.  The server does not agree.
   // No interstitial is shown.
-  MockBrowserFeatureExtractor* mock_extractor =
-      new StrictMock<MockBrowserFeatureExtractor>(web_contents());
-  SetFeatureExtractor(mock_extractor);  // The host class takes ownership.
-
   ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
   ClientPhishingRequest verdict;
   verdict.set_url("http://phishingurl.com/");
   verdict.set_client_score(1.0f);
   verdict.set_is_phishing(true);
 
-  EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
-      .WillOnce(Invoke([&](const BrowseInfo* into,
-                           std::unique_ptr<ClientPhishingRequest> request,
-                           BrowserFeatureExtractor::DoneCallback callback) {
-        request->CopyFrom(verdict);
-        std::move(callback).Run(true, std::move(request));
-      }));
-
   EXPECT_CALL(*csd_service_, SendClientReportPhishingRequest(
                                  PartiallyEqualVerdict(verdict), _, _, _))
       .WillOnce(SaveArg<3>(&cb));
@@ -510,23 +407,12 @@
 TEST_F(ClientSideDetectionHostTest, PhishingDetectionDoneDisabled) {
   // Case 2: client thinks the page is phishing and so does the server but
   // showing the interstitial is disabled => no interstitial is shown.
-  MockBrowserFeatureExtractor* mock_extractor =
-      new StrictMock<MockBrowserFeatureExtractor>(web_contents());
-  SetFeatureExtractor(mock_extractor);  // The host class takes ownership.
-
   ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
   ClientPhishingRequest verdict;
   verdict.set_url("http://phishingurl.com/");
   verdict.set_client_score(1.0f);
   verdict.set_is_phishing(true);
 
-  EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
-      .WillOnce(Invoke([&](const BrowseInfo* info,
-                           std::unique_ptr<ClientPhishingRequest> request,
-                           BrowserFeatureExtractor::DoneCallback callback) {
-        request->CopyFrom(verdict);
-        std::move(callback).Run(true, std::move(request));
-      }));
   EXPECT_CALL(*csd_service_, SendClientReportPhishingRequest(
                                  PartiallyEqualVerdict(verdict), _, _, _))
       .WillOnce(SaveArg<3>(&cb));
@@ -544,10 +430,6 @@
 TEST_F(ClientSideDetectionHostTest, PhishingDetectionDoneShowInterstitial) {
   // Case 3: client thinks the page is phishing and so does the server.
   // We show an interstitial.
-  MockBrowserFeatureExtractor* mock_extractor =
-      new StrictMock<MockBrowserFeatureExtractor>(web_contents());
-  SetFeatureExtractor(mock_extractor);  // The host class takes ownership.
-
   ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
   GURL phishing_url("http://phishingurl.com/");
   ClientPhishingRequest verdict;
@@ -555,13 +437,6 @@
   verdict.set_client_score(1.0f);
   verdict.set_is_phishing(true);
 
-  EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
-      .WillOnce(Invoke([&](const BrowseInfo* info,
-                           std::unique_ptr<ClientPhishingRequest> request,
-                           BrowserFeatureExtractor::DoneCallback callback) {
-        request->CopyFrom(verdict);
-        std::move(callback).Run(true, std::move(request));
-      }));
   EXPECT_CALL(*csd_service_, SendClientReportPhishingRequest(
                                  PartiallyEqualVerdict(verdict), _, _, _))
       .WillOnce(SaveArg<3>(&cb));
@@ -597,10 +472,6 @@
   // before the server responds with a verdict.  After a while the
   // server responds for both requests with a phishing verdict.  Only
   // a single interstitial is shown for the second URL.
-  MockBrowserFeatureExtractor* mock_extractor =
-      new StrictMock<MockBrowserFeatureExtractor>(web_contents());
-  SetFeatureExtractor(mock_extractor);  // The host class takes ownership.
-
   ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
   GURL phishing_url("http://phishingurl.com/");
   ClientPhishingRequest verdict;
@@ -608,13 +479,6 @@
   verdict.set_client_score(1.0f);
   verdict.set_is_phishing(true);
 
-  EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
-      .WillOnce(Invoke([&](const BrowseInfo* info,
-                           std::unique_ptr<ClientPhishingRequest> request,
-                           BrowserFeatureExtractor::DoneCallback callback) {
-        request->CopyFrom(verdict);
-        std::move(callback).Run(true, std::move(request));
-      }));
   EXPECT_CALL(*csd_service_, SendClientReportPhishingRequest(
                                  PartiallyEqualVerdict(verdict), _, _, _))
       .WillOnce(SaveArg<3>(&cb));
@@ -623,10 +487,6 @@
   EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
   ASSERT_FALSE(cb.is_null());
 
-  // Set this back to a normal browser feature extractor since we're using
-  // NavigateAndCommit() and it's easier to use the real thing than setting up
-  // mock expectations.
-  SetFeatureExtractor(new BrowserFeatureExtractor(web_contents()));
   GURL other_phishing_url("http://other_phishing_url.com/bla");
   ExpectPreClassificationChecks(other_phishing_url, &kFalse, &kFalse, &kFalse,
                                 &kFalse, &kFalse);
@@ -642,9 +502,6 @@
   EXPECT_CALL(*csd_service_, SendClientReportPhishingRequest(
                                  PartiallyEqualVerdict(verdict), _, _, _))
       .WillOnce(SaveArg<3>(&cb_other));
-  std::vector<GURL> redirect_chain;
-  redirect_chain.push_back(other_phishing_url);
-  SetRedirectChain(redirect_chain);
   PhishingDetectionDone(verdict.SerializeAsString());
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
@@ -678,18 +535,15 @@
 
 TEST_F(ClientSideDetectionHostTest, PhishingDetectionDoneVerdictNotPhishing) {
   // Case 6: renderer sends a verdict string that isn't phishing.
-  MockBrowserFeatureExtractor* mock_extractor =
-      new StrictMock<MockBrowserFeatureExtractor>(web_contents());
-  SetFeatureExtractor(mock_extractor);  // The host class takes ownership.
-
   ClientPhishingRequest verdict;
   verdict.set_url("http://not-phishing.com/");
   verdict.set_client_score(0.1f);
   verdict.set_is_phishing(false);
 
-  EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
+  EXPECT_CALL(*csd_service_, SendClientReportPhishingRequest(_, _, _, _))
+      .Times(0);
   PhishingDetectionDone(verdict.SerializeAsString());
-  EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
+  EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
 }
 
 TEST_F(ClientSideDetectionHostTest,
@@ -708,11 +562,7 @@
                                 &kFalse);
   NavigateAndCommit(url);
   WaitAndCheckPreClassificationChecks();
-  SetUnsafeSubResourceForCurrent(true /* expect_unsafe_resource */);
 
-  std::vector<GURL> redirect_chain;
-  redirect_chain.push_back(url);
-  SetRedirectChain(redirect_chain);
   PhishingDetectionDone(verdict.SerializeAsString());
 }
 
@@ -741,12 +591,9 @@
   EXPECT_CALL(*csd_service_, GetModelStr()).WillRepeatedly(Return("model_str"));
   ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
                                 &kFalse);
-  NavigateWithSBHitAndCommit(url);
+  NavigateAndCommit(url);
   WaitAndCheckPreClassificationChecks();
 
-  std::vector<GURL> redirect_chain;
-  redirect_chain.push_back(url);
-  SetRedirectChain(redirect_chain);
   PhishingDetectionDone(verdict.SerializeAsString());
 }
 
@@ -774,10 +621,7 @@
   EXPECT_CALL(*csd_service_, GetModelStr()).WillRepeatedly(Return("model_str"));
   ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
                                 &kFalse);
-  NavigateWithoutSBHitAndCommit(url);
-
-  // Simulate a subresource malware hit on committed page.
-  SetUnsafeSubResourceForCurrent(true /* expect_unsafe_resource */);
+  NavigateAndCommit(url);
 
   // Create a pending navigation, but don't commit it.
   GURL pending_url("http://slow.example.com/");
@@ -788,26 +632,9 @@
 
   WaitAndCheckPreClassificationChecks();
 
-  std::vector<GURL> redirect_chain;
-  redirect_chain.push_back(url);
-  SetRedirectChain(redirect_chain);
   PhishingDetectionDone(verdict.SerializeAsString());
 }
 
-TEST_F(ClientSideDetectionHostTest, SafeBrowsingHitOnFreshTab) {
-  // A fresh WebContents should not have any NavigationEntries yet. (See
-  // https://crbug.com/524208.)
-  EXPECT_EQ(nullptr, controller().GetLastCommittedEntry());
-  EXPECT_EQ(nullptr, controller().GetPendingEntry());
-
-  // Simulate a subresource malware hit (this could happen if the WebContents
-  // was created with window.open, and had content injected into it).
-  SetUnsafeSubResourceForCurrent(false /* expect_unsafe_resource */);
-
-  // If the test didn't crash, we're good. (Nothing else to test, since there
-  // was no DidNavigateMainFrame, CSD won't do anything with this hit.)
-}
-
 // This test doesn't work because it makes assumption about how
 // the message loop is run, and those assumptions are wrong when properly
 // simulating a navigation with browser-side navigations.
@@ -1051,10 +878,6 @@
 }
 
 TEST_F(ClientSideDetectionHostTest, RecordsPhishingDetectorResults) {
-  MockBrowserFeatureExtractor* mock_extractor =
-      new StrictMock<MockBrowserFeatureExtractor>(web_contents());
-  SetFeatureExtractor(mock_extractor);  // The host class takes ownership.
-
   {
     ClientPhishingRequest verdict;
     verdict.set_url("http://not-phishing.com/");
@@ -1063,9 +886,10 @@
 
     base::HistogramTester histogram_tester;
 
-    EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
+    EXPECT_CALL(*csd_service_, SendClientReportPhishingRequest(_, _, _, _))
+        .Times(0);
     PhishingDetectionDone(verdict.SerializeAsString());
-    EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
+    EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
 
     histogram_tester.ExpectUniqueSample(
         "SBClientPhishing.PhishingDetectorResult",
@@ -1075,9 +899,10 @@
   {
     base::HistogramTester histogram_tester;
 
-    EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
+    EXPECT_CALL(*csd_service_, SendClientReportPhishingRequest(_, _, _, _))
+        .Times(0);
     PhishingDetectionError(mojom::PhishingDetectorResult::CLASSIFIER_NOT_READY);
-    EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
+    EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
 
     histogram_tester.ExpectUniqueSample(
         "SBClientPhishing.PhishingDetectorResult",
@@ -1087,10 +912,11 @@
   {
     base::HistogramTester histogram_tester;
 
-    EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
+    EXPECT_CALL(*csd_service_, SendClientReportPhishingRequest(_, _, _, _))
+        .Times(0);
     PhishingDetectionError(
         mojom::PhishingDetectorResult::FORWARD_BACK_TRANSITION);
-    EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
+    EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
 
     histogram_tester.ExpectUniqueSample(
         "SBClientPhishing.PhishingDetectorResult",
@@ -1126,9 +952,6 @@
   const base::TimeDelta duration = base::TimeDelta::FromMilliseconds(10);
   AdvanceTimeTickClock(duration);
 
-  std::vector<GURL> redirect_chain;
-  redirect_chain.push_back(url);
-  SetRedirectChain(redirect_chain);
   PhishingDetectionDone(verdict.SerializeAsString());
 
   histogram_tester.ExpectTotalCount(
@@ -1154,10 +977,6 @@
   profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled,
                                     false);
 
-  MockBrowserFeatureExtractor* mock_extractor =
-      new StrictMock<MockBrowserFeatureExtractor>(web_contents());
-  SetFeatureExtractor(mock_extractor);  // The host class takes ownership.
-
   ClientPhishingRequest verdict;
   verdict.set_url("http://phishingurl.com/");
   verdict.set_client_score(1.0f);
@@ -1168,12 +987,6 @@
 
   ClientPhishingRequest request;
 
-  EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
-      .WillOnce(Invoke([&](const BrowseInfo* into,
-                           std::unique_ptr<ClientPhishingRequest> request,
-                           BrowserFeatureExtractor::DoneCallback callback) {
-        std::move(callback).Run(true, std::move(request));
-      }));
   EXPECT_CALL(*csd_service_, SendClientReportPhishingRequest(_, _, _, _))
       .WillOnce(testing::SaveArgPointee<0>(&request));
   PhishingDetectionDone(verdict.SerializeAsString());
@@ -1187,10 +1000,6 @@
   profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled,
                                     true);
 
-  MockBrowserFeatureExtractor* mock_extractor =
-      new StrictMock<MockBrowserFeatureExtractor>(web_contents());
-  SetFeatureExtractor(mock_extractor);  // The host class takes ownership.
-
   ClientPhishingRequest verdict;
   verdict.set_url("http://phishingurl.com/");
   verdict.set_client_score(1.0f);
@@ -1201,12 +1010,6 @@
 
   ClientPhishingRequest request;
 
-  EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
-      .WillOnce(Invoke([&](const BrowseInfo* into,
-                           std::unique_ptr<ClientPhishingRequest> request,
-                           BrowserFeatureExtractor::DoneCallback callback) {
-        std::move(callback).Run(true, std::move(request));
-      }));
   EXPECT_CALL(*csd_service_, SendClientReportPhishingRequest(_, _, _, _))
       .WillOnce(testing::SaveArgPointee<0>(&request));
   PhishingDetectionDone(verdict.SerializeAsString());
diff --git a/chrome/browser/search_engines/ui_thread_search_terms_data.cc b/chrome/browser/search_engines/ui_thread_search_terms_data.cc
index bcf5c7c2..b3235c01 100644
--- a/chrome/browser/search_engines/ui_thread_search_terms_data.cc
+++ b/chrome/browser/search_engines/ui_thread_search_terms_data.cc
@@ -80,14 +80,16 @@
 }
 #endif
 
-std::string UIThreadSearchTermsData::GetSuggestClient() const {
+std::string UIThreadSearchTermsData::GetSuggestClient(bool from_ntp) const {
   DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::UI) ||
       BrowserThread::CurrentlyOn(BrowserThread::UI));
 #if defined(OS_ANDROID)
+  // Android does not send non-searchbox suggest requests from NTP at this time.
+  DCHECK(!from_ntp);
   return ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_PHONE ?
       "chrome" : "chrome-omni";
 #else
-  return "chrome-omni";
+  return from_ntp ? "chrome-ntp" : "chrome-omni";
 #endif
 }
 
diff --git a/chrome/browser/search_engines/ui_thread_search_terms_data.h b/chrome/browser/search_engines/ui_thread_search_terms_data.h
index 85d29f00..d06bd96a 100644
--- a/chrome/browser/search_engines/ui_thread_search_terms_data.h
+++ b/chrome/browser/search_engines/ui_thread_search_terms_data.h
@@ -21,7 +21,7 @@
   std::string GetApplicationLocale() const override;
   base::string16 GetRlzParameterValue(bool from_app_list) const override;
   std::string GetSearchClient() const override;
-  std::string GetSuggestClient() const override;
+  std::string GetSuggestClient(bool from_ntp) const override;
   std::string GetSuggestRequestIdentifier() const override;
   std::string GoogleImageSearchSource() const override;
 
diff --git a/chrome/browser/sharesheet/sharesheet_service_factory.cc b/chrome/browser/sharesheet/sharesheet_service_factory.cc
index 4a0075e..8eeb5e2 100644
--- a/chrome/browser/sharesheet/sharesheet_service_factory.cc
+++ b/chrome/browser/sharesheet/sharesheet_service_factory.cc
@@ -20,13 +20,6 @@
 
 // static
 SharesheetService* SharesheetServiceFactory::GetForProfile(Profile* profile) {
-  // TODO: decide the right behaviour in incognito (non-guest) profiles:
-  //   - return nullptr (means we need to null check the service at call sites
-  //     OR ensure it's never accessed from an incognito profile),
-  //   - return the service attached to the Profile that the incognito profile
-  //     is branched from (i.e. "inherit" the parent service),
-  //   - return a temporary service just for the incognito session (probably
-  //     the least sensible option).
   return static_cast<SharesheetService*>(
       SharesheetServiceFactory::GetInstance()->GetServiceForBrowserContext(
           profile, true /* create */));
@@ -63,13 +56,13 @@
     return nullptr;
   }
 
-  // We allow sharing in guest mode.
+  // We allow sharing in guest mode or incognito mode..
   if (profile->IsGuestSession()) {
     return chrome::GetBrowserContextOwnInstanceInIncognito(context);
   }
 #endif  // OS_CHROMEOS
 
-  return BrowserContextKeyedServiceFactory::GetBrowserContextToUse(context);
+  return chrome::GetBrowserContextRedirectedInIncognito(context);
 }
 
 bool SharesheetServiceFactory::ServiceIsCreatedWithBrowserContext() const {
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index 555bbad9..d4dd23ae 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -3269,7 +3269,7 @@
   // And the frame should be blocked.
   bool is_content_evil = true;
   content::RenderFrameHost* content_frame = content::FrameMatchingPredicate(
-      tab, base::Bind(&content::FrameMatchesName, "contentFrame"));
+      tab, base::BindRepeating(&content::FrameMatchesName, "contentFrame"));
   std::string is_evil_js(
       "window.domAutomationController.send("
       "document.getElementById('evilDiv') != null);");
@@ -3405,7 +3405,7 @@
   // And the frame should have been blocked (see bug #2316).
   bool is_content_evil = true;
   content::RenderFrameHost* content_frame = content::FrameMatchingPredicate(
-      tab, base::Bind(&content::FrameMatchesName, "contentFrame"));
+      tab, base::BindRepeating(&content::FrameMatchesName, "contentFrame"));
   std::string is_evil_js(
       "window.domAutomationController.send("
       "document.getElementById('evilDiv') != null);");
diff --git a/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.cc b/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.cc
index 9004d53..82d46a2 100644
--- a/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.cc
@@ -119,7 +119,7 @@
 content::RenderFrameHost* SubresourceFilterBrowserTest::FindFrameByName(
     const std::string& name) const {
   return content::FrameMatchingPredicate(
-      web_contents(), base::Bind(&content::FrameMatchesName, name));
+      web_contents(), base::BindRepeating(&content::FrameMatchesName, name));
 }
 
 bool SubresourceFilterBrowserTest::WasParsedScriptElementLoaded(
diff --git a/chrome/browser/subresource_filter/subresource_filter_special_subframe_navigations_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_special_subframe_navigations_browsertest.cc
index 7d9d654..7260c6a 100644
--- a/chrome/browser/subresource_filter/subresource_filter_special_subframe_navigations_browsertest.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_special_subframe_navigations_browsertest.cc
@@ -77,7 +77,7 @@
   navigation_observer.Wait();
 
   content::RenderFrameHost* target = content::FrameMatchingPredicate(
-      web_contents(), base::Bind([](content::RenderFrameHost* rfh) {
+      web_contents(), base::BindRepeating([](content::RenderFrameHost* rfh) {
         return rfh->GetLastCommittedURL().scheme_piece() == url::kDataScheme;
       }));
   ASSERT_NE(target, nullptr);
diff --git a/chrome/browser/supervised_user/supervised_user_features.cc b/chrome/browser/supervised_user/supervised_user_features.cc
index 1c0ee95..130db69 100644
--- a/chrome/browser/supervised_user/supervised_user_features.cc
+++ b/chrome/browser/supervised_user/supervised_user_features.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/supervised_user/supervised_user_features.h"
 
+#include "base/feature_list.h"
+
 namespace supervised_users {
 
 const base::Feature kSupervisedUserIframeFilter{
@@ -15,4 +17,9 @@
 
 const base::Feature kEduCoexistenceFlowV2{"EduCoexistenceV2",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool IsEduCoexistenceFlowV2Enabled() {
+  return base::FeatureList::IsEnabled(kEduCoexistenceFlowV2);
+}
+
 }  // namespace supervised_users
diff --git a/chrome/browser/supervised_user/supervised_user_features.h b/chrome/browser/supervised_user/supervised_user_features.h
index cc1212a2..419381a 100644
--- a/chrome/browser/supervised_user/supervised_user_features.h
+++ b/chrome/browser/supervised_user/supervised_user_features.h
@@ -15,6 +15,8 @@
 
 extern const base::Feature kEduCoexistenceFlowV2;
 
+bool IsEduCoexistenceFlowV2Enabled();
+
 }  // namespace supervised_users
 
 #endif  // CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_FEATURES_H_
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index e27f0c5..b6fedc7a 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2143,6 +2143,10 @@
       "webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h",
       "webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.cc",
       "webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.h",
+      "webui/chromeos/arc_power_control/arc_power_control_handler.cc",
+      "webui/chromeos/arc_power_control/arc_power_control_handler.h",
+      "webui/chromeos/arc_power_control/arc_power_control_ui.cc",
+      "webui/chromeos/arc_power_control/arc_power_control_ui.h",
       "webui/chromeos/assistant_optin/assistant_optin_ui.cc",
       "webui/chromeos/assistant_optin/assistant_optin_ui.h",
       "webui/chromeos/assistant_optin/assistant_optin_utils.cc",
@@ -2318,6 +2322,8 @@
       "webui/chromeos/login/oobe_ui.h",
       "webui/chromeos/login/packaged_license_screen_handler.cc",
       "webui/chromeos/login/packaged_license_screen_handler.h",
+      "webui/chromeos/login/parental_handoff_screen_handler.cc",
+      "webui/chromeos/login/parental_handoff_screen_handler.h",
       "webui/chromeos/login/recommend_apps_screen_handler.cc",
       "webui/chromeos/login/recommend_apps_screen_handler.h",
       "webui/chromeos/login/reset_screen_handler.cc",
diff --git a/chrome/browser/ui/android/native_page/BUILD.gn b/chrome/browser/ui/android/native_page/BUILD.gn
index 01c80a96..85cfe3c 100644
--- a/chrome/browser/ui/android/native_page/BUILD.gn
+++ b/chrome/browser/ui/android/native_page/BUILD.gn
@@ -13,6 +13,8 @@
   deps = [
     "//base:base_java",
     "//components/browser_ui/styles/android:java",
+    "//components/embedder_support/android:util_java",
     "//content/public/android:content_java",
+    "//third_party/android_deps:androidx_annotation_annotation_java",
   ]
 }
diff --git a/chrome/browser/ui/android/native_page/DEPS b/chrome/browser/ui/android/native_page/DEPS
index 2d0aef2..78dd1a2 100644
--- a/chrome/browser/ui/android/native_page/DEPS
+++ b/chrome/browser/ui/android/native_page/DEPS
@@ -2,5 +2,6 @@
 include_rules = [
   "+base/android",
   "+components/browser_ui/styles/android",
+  "+components/embedder_support/android",
   "+content/public/android",
 ]
diff --git a/chrome/browser/ui/android/native_page/java/src/org/chromium/chrome/browser/ui/native_page/NativePage.java b/chrome/browser/ui/android/native_page/java/src/org/chromium/chrome/browser/ui/native_page/NativePage.java
index 49add778..93a97756 100644
--- a/chrome/browser/ui/android/native_page/java/src/org/chromium/chrome/browser/ui/native_page/NativePage.java
+++ b/chrome/browser/ui/android/native_page/java/src/org/chromium/chrome/browser/ui/native_page/NativePage.java
@@ -4,8 +4,16 @@
 
 package org.chromium.chrome.browser.ui.native_page;
 
+import android.net.Uri;
 import android.view.View;
 
+import androidx.annotation.IntDef;
+
+import org.chromium.components.embedder_support.util.UrlConstants;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * An interface for pages that will be using Android views instead of html/rendered Web content.
  */
@@ -56,4 +64,69 @@
      * Called after a page has been removed from the view hierarchy and will no longer be used.
      */
     void destroy();
+
+    @IntDef({NativePageType.NONE, NativePageType.CANDIDATE, NativePageType.NTP,
+            NativePageType.BOOKMARKS, NativePageType.RECENT_TABS, NativePageType.DOWNLOADS,
+            NativePageType.HISTORY, NativePageType.EXPLORE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NativePageType {
+        int NONE = 0;
+        int CANDIDATE = 1;
+        int NTP = 2;
+        int BOOKMARKS = 3;
+        int RECENT_TABS = 4;
+        int DOWNLOADS = 5;
+        int HISTORY = 6;
+        int EXPLORE = 7;
+    }
+
+    /**
+     * Returns whether the URL would navigate to a native page.
+     *
+     * @param url The URL to be checked.
+     * @param isIncognito Whether the page will be displayed in incognito mode.
+     * @return Whether the host and the scheme of the passed in URL matches one of the supported
+     *         native pages.
+     */
+    public static boolean isNativePageUrl(String url, boolean isIncognito) {
+        return nativePageType(url, null, isIncognito) != NativePageType.NONE;
+    }
+
+    /**
+     * @param url The URL to be checked.
+     * @param candidatePage NativePage to return as result if the host is matched.
+     * @param isIncognito Whether the page will be displayed in incognito mode.
+     * @return Type of the native page defined in {@link NativePageType}.
+     */
+    public static @NativePageType int nativePageType(
+            String url, NativePage candidatePage, boolean isIncognito) {
+        if (url == null) return NativePageType.NONE;
+
+        Uri uri = Uri.parse(url);
+        if (!UrlConstants.CHROME_NATIVE_SCHEME.equals(uri.getScheme())
+                && !UrlConstants.CHROME_SCHEME.equals(uri.getScheme())) {
+            return NativePageType.NONE;
+        }
+
+        String host = uri.getHost();
+        if (candidatePage != null && candidatePage.getHost().equals(host)) {
+            return NativePageType.CANDIDATE;
+        }
+
+        if (UrlConstants.NTP_HOST.equals(host)) {
+            return NativePageType.NTP;
+        } else if (UrlConstants.BOOKMARKS_HOST.equals(host)) {
+            return NativePageType.BOOKMARKS;
+        } else if (UrlConstants.DOWNLOADS_HOST.equals(host)) {
+            return NativePageType.DOWNLOADS;
+        } else if (UrlConstants.HISTORY_HOST.equals(host)) {
+            return NativePageType.HISTORY;
+        } else if (UrlConstants.RECENT_TABS_HOST.equals(host) && !isIncognito) {
+            return NativePageType.RECENT_TABS;
+        } else if (UrlConstants.EXPLORE_HOST.equals(host)) {
+            return NativePageType.EXPLORE;
+        } else {
+            return NativePageType.NONE;
+        }
+    }
 }
diff --git a/chrome/browser/ui/app_list/search/cros_action_history/cros_action_recorder_tab_tracker_unittest.cc b/chrome/browser/ui/app_list/search/cros_action_history/cros_action_recorder_tab_tracker_unittest.cc
index da7c0b2..45aee46 100644
--- a/chrome/browser/ui/app_list/search/cros_action_history/cros_action_recorder_tab_tracker_unittest.cc
+++ b/chrome/browser/ui/app_list/search/cros_action_history/cros_action_recorder_tab_tracker_unittest.cc
@@ -38,15 +38,14 @@
     CrOSActionRecorder::GetCrosActionRecorder()->Init(profile());
 
     // Initialize browser.
-    params_ = std::make_unique<Browser::CreateParams>(profile(), true);
-    browser_ = CreateBrowserWithTestWindowForParams(params_.get());
+    browser_ = CreateBrowserWithTestWindowForParams(
+        Browser::CreateParams(profile(), true));
     tab_strip_model_ = browser_->tab_strip_model();
   }
 
   void TearDown() override {
     tab_strip_model_->CloseAllTabs();
     browser_.reset();
-    params_.reset();
     ChromeRenderViewHostTestHarness::TearDown();
   }
 
@@ -75,7 +74,6 @@
 
   TabActivitySimulator tab_activity_simulator_;
   TabStripModel* tab_strip_model_;
-  std::unique_ptr<Browser::CreateParams> params_;
   std::unique_ptr<Browser> browser_;
 };
 
diff --git a/chrome/browser/ui/app_list/search/omnibox_result.cc b/chrome/browser/ui/app_list/search/omnibox_result.cc
index 7bda404..84e75db 100644
--- a/chrome/browser/ui/app_list/search/omnibox_result.cc
+++ b/chrome/browser/ui/app_list/search/omnibox_result.cc
@@ -151,7 +151,7 @@
       match_(match),
       is_zero_suggestion_(is_zero_suggestion) {
   if (match_.search_terms_args && autocomplete_controller_) {
-    match_.search_terms_args->from_app_list = true;
+    match_.search_terms_args->request_source = TemplateURLRef::CROS_APP_LIST;
     autocomplete_controller_->UpdateMatchDestinationURL(
         *match_.search_terms_args, &match_);
   }
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index e64857a..30a8f5ee 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -1935,10 +1935,6 @@
   FileSelectHelper::EnumerateDirectory(web_contents, std::move(listener), path);
 }
 
-bool Browser::EmbedsFullscreenWidget() {
-  return true;
-}
-
 void Browser::EnterFullscreenModeForTab(
     content::RenderFrameHost* requesting_frame,
     const blink::mojom::FullscreenOptions& options) {
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index c67b79ec..79cde7e1 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -816,7 +816,6 @@
   void EnumerateDirectory(content::WebContents* web_contents,
                           scoped_refptr<content::FileSelectListener> listener,
                           const base::FilePath& path) override;
-  bool EmbedsFullscreenWidget() override;
   void EnterFullscreenModeForTab(
       content::RenderFrameHost* requesting_frame,
       const blink::mojom::FullscreenOptions& options) override;
diff --git a/chrome/browser/ui/browser_command_controller_unittest.cc b/chrome/browser/ui/browser_command_controller_unittest.cc
index 8505e438..9abe0c4 100644
--- a/chrome/browser/ui/browser_command_controller_unittest.cc
+++ b/chrome/browser/ui/browser_command_controller_unittest.cc
@@ -239,7 +239,7 @@
   Browser::CreateParams profile_params(original_profile->GetPrimaryOTRProfile(),
                                        true);
   std::unique_ptr<Browser> otr_browser(
-      CreateBrowserWithTestWindowForParams(&profile_params));
+      CreateBrowserWithTestWindowForParams(profile_params));
 
   chrome::BrowserCommandController command_controller(otr_browser.get());
   const CommandUpdater* command_updater = &command_controller;
@@ -489,7 +489,7 @@
   // Create a new browser based on the off the record profile.
   Browser::CreateParams profile_params(profile1->GetPrimaryOTRProfile(), true);
   std::unique_ptr<Browser> browser2(
-      CreateBrowserWithTestWindowForParams(&profile_params));
+      CreateBrowserWithTestWindowForParams(profile_params));
 
   chrome::BrowserCommandController command_controller(browser2.get());
   const CommandUpdater* command_updater = &command_controller;
diff --git a/chrome/browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm b/chrome/browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm
index c56296e..dbf4dc9 100644
--- a/chrome/browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm
@@ -203,7 +203,7 @@
   // Create a browser and "show" it.
   Browser::CreateParams profile2_params(profile2, true);
   std::unique_ptr<Browser> p2_browser(
-      CreateBrowserWithTestWindowForParams(&profile2_params));
+      CreateBrowserWithTestWindowForParams(profile2_params));
   [controller() activeBrowserChangedTo:p2_browser.get()];
   VerifyProfileNamedIsActive(@"Profile 2", __LINE__);
 
@@ -215,7 +215,7 @@
   // Open a new browser and make sure it takes effect.
   Browser::CreateParams profile3_params(profile3, true);
   std::unique_ptr<Browser> p3_browser(
-      CreateBrowserWithTestWindowForParams(&profile3_params));
+      CreateBrowserWithTestWindowForParams(profile3_params));
   [controller() activeBrowserChangedTo:p3_browser.get()];
   VerifyProfileNamedIsActive(@"Profile 3", __LINE__);
 
diff --git a/chrome/browser/ui/cocoa/tab_contents/chrome_web_contents_view_delegate_mac.mm b/chrome/browser/ui/cocoa/tab_contents/chrome_web_contents_view_delegate_mac.mm
index 267c08f..8feffd3 100644
--- a/chrome/browser/ui/cocoa/tab_contents/chrome_web_contents_view_delegate_mac.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/chrome_web_contents_view_delegate_mac.mm
@@ -135,9 +135,7 @@
 
 content::RenderWidgetHostView*
 ChromeWebContentsViewDelegateMac::GetActiveRenderWidgetHostView() const {
-  return web_contents_->GetFullscreenRenderWidgetHostView() ?
-      web_contents_->GetFullscreenRenderWidgetHostView() :
-      web_contents_->GetTopLevelRenderWidgetHostView();
+  return web_contents_->GetTopLevelRenderWidgetHostView();
 }
 
 NSWindow* ChromeWebContentsViewDelegateMac::GetNSWindowForFocusTracker() const {
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_manager.cc b/chrome/browser/ui/exclusive_access/exclusive_access_manager.cc
index 164d2667..b47f2aff 100644
--- a/chrome/browser/ui/exclusive_access/exclusive_access_manager.cc
+++ b/chrome/browser/ui/exclusive_access/exclusive_access_manager.cc
@@ -44,8 +44,7 @@
     if (!fullscreen_controller_.IsTabFullscreen())
       return EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_EXIT_INSTRUCTION;
 
-    if (mouse_lock_controller_.IsMouseLockedSilently() ||
-        fullscreen_controller_.IsPrivilegedFullscreenForTab()) {
+    if (mouse_lock_controller_.IsMouseLockedSilently()) {
       return EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE;
     }
 
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_test.cc b/chrome/browser/ui/exclusive_access/exclusive_access_test.cc
index 916cebe..b24ba9f3 100644
--- a/chrome/browser/ui/exclusive_access/exclusive_access_test.cc
+++ b/chrome/browser/ui/exclusive_access/exclusive_access_test.cc
@@ -183,10 +183,6 @@
   observer.Wait();
 }
 
-void ExclusiveAccessTest::SetPrivilegedFullscreen(bool is_privileged) {
-  GetFullscreenController()->SetPrivilegedFullscreenForTesting(is_privileged);
-}
-
 void ExclusiveAccessTest::EnterActiveTabFullscreen() {
   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
   FullscreenNotificationObserver fullscreen_observer(browser());
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_test.h b/chrome/browser/ui/exclusive_access/exclusive_access_test.h
index f0f5bc7..9f4803d9 100644
--- a/chrome/browser/ui/exclusive_access/exclusive_access_test.h
+++ b/chrome/browser/ui/exclusive_access/exclusive_access_test.h
@@ -74,7 +74,6 @@
   bool IsExclusiveAccessBubbleDisplayed();
   void GoBack();
   void Reload();
-  void SetPrivilegedFullscreen(bool is_privileged);
   void EnterActiveTabFullscreen();
   void ToggleBrowserFullscreen();
   void EnterExtensionInitiatedFullscreen();
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
index c954e018..4ac576c 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
@@ -239,10 +239,6 @@
     return;
   }
 
-  content::RenderWidgetHostView* const current_fs_view =
-      old_contents->GetFullscreenRenderWidgetHostView();
-  if (current_fs_view)
-    current_fs_view->SetSize(old_contents->GetPreferredSize());
   old_contents->Resize(gfx::Rect(old_contents->GetPreferredSize()));
 }
 
@@ -426,18 +422,6 @@
       ExclusiveAccessBubbleHideCallback());
 }
 
-bool FullscreenController::IsPrivilegedFullscreenForTab() const {
-  const bool embedded_widget_present =
-      exclusive_access_tab() &&
-      exclusive_access_tab()->GetFullscreenRenderWidgetHostView();
-  return embedded_widget_present || is_privileged_fullscreen_for_testing_;
-}
-
-void FullscreenController::SetPrivilegedFullscreenForTesting(
-    bool is_privileged) {
-  is_privileged_fullscreen_for_testing_ = is_privileged;
-}
-
 bool FullscreenController::MaybeToggleFullscreenWithinTab(
     WebContents* web_contents,
     bool enter_fullscreen) {
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.h b/chrome/browser/ui/exclusive_access/fullscreen_controller.h
index 9a78155..772d5ba 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.h
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.h
@@ -67,9 +67,6 @@
   // transition.
   bool IsFullscreenForBrowser() const;
 
-  // Returns true if Flash is providing the "exit from fullscreen" message.
-  bool IsPrivilegedFullscreenForTab() const;
-
   void ToggleBrowserFullscreenMode();
 
   // Extension API implementation uses this method to toggle fullscreen mode.
@@ -169,7 +166,6 @@
   void ExitFullscreenModeInternal();
   void SetFullscreenedTab(content::WebContents* tab, const GURL& origin);
 
-  void SetPrivilegedFullscreenForTesting(bool is_privileged);
   // Returns true if |web_contents| was toggled into/out of fullscreen mode as a
   // screen-captured tab or as a content-fullscreen tab.
   // See 'FullscreenWithinTab Note'.
@@ -205,10 +201,6 @@
   // deactivation of a tab.
   content::WebContents* deactivated_contents_ = nullptr;
 
-  // Used in testing to confirm proper behavior for specific, privileged
-  // fullscreen cases.
-  bool is_privileged_fullscreen_for_testing_ = false;
-
   // Used in testing to set the state to tab fullscreen.
   bool is_tab_fullscreen_for_testing_ = false;
 
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
index 548e38f..5a97487 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
@@ -415,37 +415,6 @@
   ASSERT_TRUE(IsWindowFullscreenForTabOrPending());
 }
 
-// Tests mouse lock and fullscreen for the privileged fullscreen case (e.g.,
-// embedded flash fullscreen, since the Flash plugin handles user permissions
-// requests itself).
-// Flaky on Linux: crbug.com/1066607
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC)
-#define MAYBE_PrivilegedMouseLockAndFullscreen \
-  DISABLED_PrivilegedMouseLockAndFullscreen
-#else
-#define MAYBE_PrivilegedMouseLockAndFullscreen PrivilegedMouseLockAndFullscreen
-#endif
-IN_PROC_BROWSER_TEST_F(FullscreenControllerInteractiveTest,
-                       MAYBE_PrivilegedMouseLockAndFullscreen) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  ui_test_utils::NavigateToURL(
-      browser(), embedded_test_server()->GetURL(kFullscreenMouseLockHTML));
-
-  ASSERT_FALSE(IsExclusiveAccessBubbleDisplayed());
-
-  SetPrivilegedFullscreen(true);
-
-  // Request to lock the mouse and enter fullscreen.
-  FullscreenNotificationObserver fullscreen_observer(browser());
-  PressKeyAndWaitForMouseLockRequest(ui::VKEY_B);
-  fullscreen_observer.Wait();
-
-  // Confirm they are enabled and there is no prompt.
-  ASSERT_FALSE(IsExclusiveAccessBubbleDisplayed());
-  ASSERT_TRUE(IsMouseLocked());
-  ASSERT_TRUE(IsWindowFullscreenForTabOrPending());
-}
-
 // Flaky on Linux, CrOS: http://crbug.com/159000
 // Flaky on Windows; see https://crbug.com/791539.
 // Flaky on Mac: https://crbug.com/876617.
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc
index 0d2240d..93b1909e 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc
@@ -484,7 +484,6 @@
 TEST_F(FullscreenControllerStateUnitTest, OneCapturedFullscreenedTab) {
   content::WebContentsDelegate* const wc_delegate =
       static_cast<content::WebContentsDelegate*>(browser());
-  ASSERT_TRUE(wc_delegate->EmbedsFullscreenWidget());
 
   AddTab(browser(), GURL(url::kAboutBlankURL));
   AddTab(browser(), GURL(url::kAboutBlankURL));
@@ -551,7 +550,6 @@
 TEST_F(FullscreenControllerStateUnitTest, TwoFullscreenedTabsOneCaptured) {
   content::WebContentsDelegate* const wc_delegate =
       static_cast<content::WebContentsDelegate*>(browser());
-  ASSERT_TRUE(wc_delegate->EmbedsFullscreenWidget());
 
   AddTab(browser(), GURL(url::kAboutBlankURL));
   AddTab(browser(), GURL(url::kAboutBlankURL));
@@ -612,7 +610,6 @@
        BackgroundCapturedTabExitsFullscreen) {
   content::WebContentsDelegate* const wc_delegate =
       static_cast<content::WebContentsDelegate*>(browser());
-  ASSERT_TRUE(wc_delegate->EmbedsFullscreenWidget());
 
   AddTab(browser(), GURL(url::kAboutBlankURL));
   AddTab(browser(), GURL(url::kAboutBlankURL));
@@ -670,7 +667,6 @@
        OneCapturedTabFullscreenedBeforeBrowserFullscreen) {
   content::WebContentsDelegate* const wc_delegate =
       static_cast<content::WebContentsDelegate*>(browser());
-  ASSERT_TRUE(wc_delegate->EmbedsFullscreenWidget());
 
   AddTab(browser(), GURL(url::kAboutBlankURL));
   content::WebContents* const tab =
@@ -719,7 +715,6 @@
 TEST_F(FullscreenControllerStateUnitTest, HiddenlyCapturedTabFullscreened) {
   content::WebContentsDelegate* const wc_delegate =
       static_cast<content::WebContentsDelegate*>(browser());
-  ASSERT_TRUE(wc_delegate->EmbedsFullscreenWidget());
 
   AddTab(browser(), GURL(url::kAboutBlankURL));
   content::WebContents* const tab =
@@ -803,7 +798,6 @@
        CapturedFullscreenedTabTransferredBetweenBrowserWindows) {
   content::WebContentsDelegate* const wc_delegate =
       static_cast<content::WebContentsDelegate*>(browser());
-  ASSERT_TRUE(wc_delegate->EmbedsFullscreenWidget());
 
   AddTab(browser(), GURL(url::kAboutBlankURL));
   AddTab(browser(), GURL(url::kAboutBlankURL));
diff --git a/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc b/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc
index 993367d..163c276d 100644
--- a/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc
+++ b/chrome/browser/ui/exclusive_access/mouse_lock_controller.cc
@@ -155,19 +155,9 @@
     return;
 
   content::RenderWidgetHostView* mouse_lock_view = nullptr;
-  FullscreenController* fullscreen_controller =
-      exclusive_access_manager()->fullscreen_controller();
-  if ((fullscreen_controller->exclusive_access_tab() == tab) &&
-      fullscreen_controller->IsPrivilegedFullscreenForTab()) {
-    mouse_lock_view =
-        exclusive_access_tab()->GetFullscreenRenderWidgetHostView();
-  }
-
-  if (!mouse_lock_view) {
-    RenderViewHost* const rvh = exclusive_access_tab()->GetRenderViewHost();
-    if (rvh)
-      mouse_lock_view = rvh->GetWidget()->GetView();
-  }
+  RenderViewHost* const rvh = exclusive_access_tab()->GetRenderViewHost();
+  if (rvh)
+    mouse_lock_view = rvh->GetWidget()->GetView();
 
   if (mouse_lock_view)
     mouse_lock_view->UnlockMouse();
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
index a19e6d6..6f37d81 100644
--- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -832,7 +832,7 @@
     nav_observer.Wait();
 
     RenderFrameHost* subframe = content::FrameMatchingPredicate(
-        web_contents, base::Bind(&content::FrameHasSourceUrl, url));
+        web_contents, base::BindRepeating(&content::FrameHasSourceUrl, url));
 
     EXPECT_EQ(expect_same_process,
               parent_rfh->GetProcess() == subframe->GetProcess())
@@ -886,7 +886,7 @@
 
   auto find_frame = [web_contents](const std::string& name) {
     return content::FrameMatchingPredicate(
-        web_contents, base::Bind(&content::FrameMatchesName, name));
+        web_contents, base::BindRepeating(&content::FrameMatchesName, name));
   };
   RenderFrameHost* app = web_contents->GetMainFrame();
   RenderFrameHost* same_dir = find_frame("SameOrigin-SamePath");
@@ -1069,7 +1069,7 @@
 
   auto find_frame = [web_contents](const std::string& name) {
     return content::FrameMatchingPredicate(
-        web_contents, base::Bind(&content::FrameMatchesName, name));
+        web_contents, base::BindRepeating(&content::FrameMatchesName, name));
   };
   RenderFrameHost* app = web_contents->GetMainFrame();
   RenderFrameHost* same_dir = find_frame("SameOrigin-SamePath");
diff --git a/chrome/browser/ui/tab_contents/tab_contents_iterator_unittest.cc b/chrome/browser/ui/tab_contents/tab_contents_iterator_unittest.cc
index a7c97de..b60edccf 100644
--- a/chrome/browser/ui/tab_contents/tab_contents_iterator_unittest.cc
+++ b/chrome/browser/ui/tab_contents/tab_contents_iterator_unittest.cc
@@ -36,14 +36,14 @@
   // Create more browsers/windows.
   Browser::CreateParams native_params(profile(), true);
   std::unique_ptr<Browser> browser2(
-      CreateBrowserWithTestWindowForParams(&native_params));
+      CreateBrowserWithTestWindowForParams(native_params));
   // Create browser 3 and 4 on the Ash desktop (the iterator shouldn't see the
   // difference).
   Browser::CreateParams ash_params(profile(), true);
   std::unique_ptr<Browser> browser3(
-      CreateBrowserWithTestWindowForParams(&ash_params));
+      CreateBrowserWithTestWindowForParams(ash_params));
   std::unique_ptr<Browser> browser4(
-      CreateBrowserWithTestWindowForParams(&ash_params));
+      CreateBrowserWithTestWindowForParams(ash_params));
 
   // Sanity checks.
   EXPECT_EQ(4U, BrowserList::GetInstance()->size());
@@ -82,12 +82,12 @@
   // Create more browsers/windows.
   Browser::CreateParams native_params(profile(), true);
   std::unique_ptr<Browser> browser2(
-      CreateBrowserWithTestWindowForParams(&native_params));
+      CreateBrowserWithTestWindowForParams(native_params));
   // Create browser 3 on the Ash desktop (the iterator shouldn't see the
   // difference).
   Browser::CreateParams ash_params(profile(), true);
   std::unique_ptr<Browser> browser3(
-      CreateBrowserWithTestWindowForParams(&ash_params));
+      CreateBrowserWithTestWindowForParams(ash_params));
 
   // Sanity checks.
   EXPECT_EQ(3U, BrowserList::GetInstance()->size());
diff --git a/chrome/browser/ui/tabs/pinned_tab_service_unittest.cc b/chrome/browser/ui/tabs/pinned_tab_service_unittest.cc
index 0218672e..2c19b7a 100644
--- a/chrome/browser/ui/tabs/pinned_tab_service_unittest.cc
+++ b/chrome/browser/ui/tabs/pinned_tab_service_unittest.cc
@@ -57,7 +57,7 @@
 
   // Create a popup.
   Browser::CreateParams params(Browser::TYPE_POPUP, profile(), true);
-  std::unique_ptr<Browser> popup(CreateBrowserWithTestWindowForParams(&params));
+  std::unique_ptr<Browser> popup(CreateBrowserWithTestWindowForParams(params));
 
   // Close the browser. This should trigger saving the tabs. No need to destroy
   // the browser (this happens automatically in the test destructor).
diff --git a/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc b/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc
index cc8b8b9e..500760c 100644
--- a/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc
@@ -503,7 +503,7 @@
 TEST_F(BackFwdMenuModelTest, FaviconLoadTest) {
   Browser::CreateParams native_params(profile(), true);
   std::unique_ptr<Browser> browser(
-      CreateBrowserWithTestWindowForParams(&native_params));
+      CreateBrowserWithTestWindowForParams(native_params));
   FaviconDelegate favicon_delegate;
 
   BackForwardMenuModel back_model(browser.get(),
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index a6ac57e..1a971b23 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -105,10 +105,6 @@
 const base::Feature kTabSearchFeedback{"TabSearchFeedback",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enables the tab search bubble having a fixed tab strip position.
-const base::Feature kTabSearchFixedEntrypoint{
-    "TabSearchFixedEntrypoint", base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::FeatureParam<bool> kTabSearchSearchIgnoreLocation{
     &kTabSearch, "TabSearchSearchIgnoreLocation", true};
 
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h
index b0b7c2b..46dc15e 100644
--- a/chrome/browser/ui/ui_features.h
+++ b/chrome/browser/ui/ui_features.h
@@ -64,8 +64,6 @@
 
 extern const base::Feature kTabSearchFeedback;
 
-extern const base::Feature kTabSearchFixedEntrypoint;
-
 // Setting this to true will ignore the distance parameter when finding matches.
 // This means that it will not matter where in the string the pattern occurs.
 extern const base::FeatureParam<bool> kTabSearchSearchIgnoreLocation;
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
index f129911..4f5c9e8 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
@@ -304,7 +304,7 @@
     profile_->GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, true);
 
     Browser::CreateParams native_params(profile_.get(), true);
-    browser_ = CreateBrowserWithTestWindowForParams(&native_params);
+    browser_ = CreateBrowserWithTestWindowForParams(native_params);
 
     model_->ClearStore();
 
diff --git a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
index 72daf509..bf0f5d2 100644
--- a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
+++ b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
@@ -775,7 +775,8 @@
 
   content::RenderFrameHost* GetFrameByName(const std::string& name_to_find) {
     return content::FrameMatchingPredicate(
-        web_contents(), base::Bind(&content::FrameMatchesName, name_to_find));
+        web_contents(),
+        base::BindRepeating(&content::FrameMatchesName, name_to_find));
   }
 
   void AssertTestPageIsLoaded() {
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 95268afb..c5382a84 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -589,7 +589,6 @@
   auto contents_web_view =
       std::make_unique<ContentsWebView>(browser_->profile());
   contents_web_view->SetID(VIEW_ID_TAB_CONTAINER);
-  contents_web_view->SetEmbedFullscreenWidgetMode(true);
 
   auto contents_container = std::make_unique<views::View>();
   devtools_web_view_ =
@@ -736,16 +735,9 @@
 }
 
 TabSearchButton* BrowserView::GetTabSearchButton() {
-  if (!base::FeatureList::IsEnabled(features::kTabSearch))
-    return nullptr;
-
-  // If kTabSearchFixedEntrypoint is enabled then the tab search button is
-  // defined in the tab strip region view.
-  // TODO(tluk): Consolidate these once Tab Scrolling successfully moves the
-  // tab controls container to the tab strip region view.
-  return base::FeatureList::IsEnabled(features::kTabSearchFixedEntrypoint)
+  return base::FeatureList::IsEnabled(features::kTabSearch)
              ? tab_strip_region_view_->tab_search_button()
-             : tabstrip_->tab_search_button();
+             : nullptr;
 }
 
 bool BrowserView::IsTabStripVisible() const {
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index 78e57dc..33f0766 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -536,8 +536,8 @@
     views::CaptionButtonIcon icon_type,
     int ht_component,
     const gfx::VectorIcon& icon_image) {
-  views::FrameCaptionButton* button =
-      new views::FrameCaptionButton(nullptr, icon_type, ht_component);
+  views::FrameCaptionButton* button = new views::FrameCaptionButton(
+      views::Button::PressedCallback(), icon_type, ht_component);
   button->SetImage(button->icon(), views::FrameCaptionButton::ANIMATE_NO,
                    icon_image);
   return button;
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view.cc b/chrome/browser/ui/views/frame/tab_strip_region_view.cc
index a43ec6f..6e75cdd 100644
--- a/chrome/browser/ui/views/frame/tab_strip_region_view.cc
+++ b/chrome/browser/ui/views/frame/tab_strip_region_view.cc
@@ -107,7 +107,6 @@
                                views::MaximumFlexSizeRule::kUnbounded));
 
   if (base::FeatureList::IsEnabled(features::kTabSearch) &&
-      base::FeatureList::IsEnabled(features::kTabSearchFixedEntrypoint) &&
       !tab_strip_->controller()->GetProfile()->IsIncognitoProfile()) {
     auto tab_search_button = std::make_unique<TabSearchButton>(tab_strip_);
     tab_search_button->SetTooltipText(
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc
index 6ad65f6f..2968701 100644
--- a/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc
@@ -28,11 +28,9 @@
   void SetUp() override {
     // Run the test with both kTabSearchFixedEntrypoint enabled and disabled.
     if (GetParam()) {
-      scoped_feature_list_.InitWithFeatures(
-          {features::kTabSearch, features::kTabSearchFixedEntrypoint}, {});
+      scoped_feature_list_.InitWithFeatures({features::kTabSearch}, {});
     } else {
-      scoped_feature_list_.InitWithFeatures(
-          {}, {features::kTabSearch, features::kTabSearchFixedEntrypoint});
+      scoped_feature_list_.InitWithFeatures({}, {features::kTabSearch});
     }
     InProcessBrowserTest::SetUp();
   }
@@ -178,8 +176,7 @@
 
 IN_PROC_BROWSER_TEST_P(TabStripRegionViewBrowserTest,
                        TestSearchButtonIsEndAligned) {
-  if (base::FeatureList::IsEnabled(features::kTabSearch) &&
-      base::FeatureList::IsEnabled(features::kTabSearchFixedEntrypoint)) {
+  if (base::FeatureList::IsEnabled(features::kTabSearch)) {
     EXPECT_EQ(tab_strip_region_view()->GetLocalBounds().right(),
               tab_search_button()->bounds().right());
   }
diff --git a/chrome/browser/ui/views/read_later/read_later_bubble_view.cc b/chrome/browser/ui/views/read_later/read_later_bubble_view.cc
index 752fa70..76f30d2 100644
--- a/chrome/browser/ui/views/read_later/read_later_bubble_view.cc
+++ b/chrome/browser/ui/views/read_later/read_later_bubble_view.cc
@@ -17,17 +17,7 @@
 #include "ui/views/controls/webview/webview.h"
 #include "ui/views/layout/fill_layout.h"
 
-namespace {
-// ReadLaterWebView ---------------------------------------------------------
-class ReadLaterWebView : public views::WebView {
- public:
-  explicit ReadLaterWebView(content::BrowserContext* context)
-      : views::WebView(context) {}
-  ReadLaterWebView(const ReadLaterWebView&) = delete;
-  ReadLaterWebView& operator=(const ReadLaterWebView&) = delete;
-};
-
-}  // namespace
+#include "chrome/browser/ui/webui/read_later/read_later_ui.h"
 
 // ReadLaterBubbleView ---------------------------------------------------------
 
@@ -35,35 +25,19 @@
 base::WeakPtr<ReadLaterBubbleView> ReadLaterBubbleView::Show(
     const Browser* browser,
     views::View* anchor_view) {
-  ReadLaterBubbleView* bubble = new ReadLaterBubbleView(browser, anchor_view);
-  views::Widget* const widget = BubbleDialogDelegateView::CreateBubble(bubble);
-  widget->Show();
-  return bubble->weak_factory_.GetWeakPtr();
+  auto bubble_view =
+      std::make_unique<ReadLaterBubbleView>(browser, anchor_view);
+  auto weak_ptr = bubble_view->weak_factory_.GetWeakPtr();
+  views::WebBubbleDialogView::CreateWebBubbleDialog<ReadLaterUI>(
+      std::move(bubble_view), GURL(chrome::kChromeUIReadLaterURL));
+  return weak_ptr;
 }
 
 ReadLaterBubbleView::ReadLaterBubbleView(const Browser* browser,
                                          views::View* anchor_view)
-    : BubbleDialogDelegateView(anchor_view,
-                               views::BubbleBorder::Arrow::TOP_RIGHT),
-      web_view_(std::make_unique<ReadLaterWebView>(browser->profile())) {
-  SetButtons(ui::DIALOG_BUTTON_NONE);
-  set_margins(gfx::Insets());
-
-  AddChildView(web_view_.get());
-
-  SetLayoutManager(std::make_unique<views::FillLayout>());
-
-  // TODO(corising): Remove this and add function to calculate preferred size.
-  web_view_->SetPreferredSize(gfx::Size(300, 500));
-  web_view_->LoadInitialURL(GURL(chrome::kChromeUIReadLaterURL));
-}
+    : WebBubbleDialogView(browser->profile(), anchor_view) {}
 
 ReadLaterBubbleView::~ReadLaterBubbleView() = default;
 
-void ReadLaterBubbleView::AddedToWidget() {
-  BubbleDialogDelegateView::AddedToWidget();
-  web_view_->holder()->SetCornerRadii(gfx::RoundedCornersF(GetCornerRadius()));
-}
-
 void ReadLaterBubbleView::ReadingListModelLoaded(
     const ReadingListModel* model) {}
diff --git a/chrome/browser/ui/views/read_later/read_later_bubble_view.h b/chrome/browser/ui/views/read_later/read_later_bubble_view.h
index 577454b..fd12bac5 100644
--- a/chrome/browser/ui/views/read_later/read_later_bubble_view.h
+++ b/chrome/browser/ui/views/read_later/read_later_bubble_view.h
@@ -7,41 +7,29 @@
 
 #include <memory>
 
-#include "base/memory/weak_ptr.h"
 #include "components/reading_list/core/reading_list_model_observer.h"
-#include "ui/views/bubble/bubble_dialog_delegate_view.h"
-
-namespace views {
-class WebView;
-}
+#include "ui/views/controls/webview/web_bubble_dialog_view.h"
 
 class Browser;
 
 // This bubble view displays a list of read-later entries.
 // This class is only used with the kReadLater feature.
-class ReadLaterBubbleView : public views::BubbleDialogDelegateView,
+class ReadLaterBubbleView : public views::WebBubbleDialogView,
                             public ReadingListModelObserver {
  public:
-  ReadLaterBubbleView(const ReadLaterBubbleView&) = delete;
-  ReadLaterBubbleView& operator=(const ReadLaterBubbleView&) = delete;
-
   // Displays the read-later dialog under |anchor_view|, attached to |browser|.
   static base::WeakPtr<ReadLaterBubbleView> Show(const Browser* browser,
                                                  views::View* anchor_view);
 
- private:
   ReadLaterBubbleView(const Browser* browser, views::View* anchor_view);
-
+  ReadLaterBubbleView(const ReadLaterBubbleView&) = delete;
+  ReadLaterBubbleView& operator=(const ReadLaterBubbleView&) = delete;
   ~ReadLaterBubbleView() override;
 
-  // views::BubbleDialogDelegateView:
-  void AddedToWidget() override;
-
+ private:
   // ReadingListModelObserver:
   void ReadingListModelLoaded(const ReadingListModel* model) override;
 
-  std::unique_ptr<views::WebView> const web_view_;
-
   base::WeakPtrFactory<ReadLaterBubbleView> weak_factory_{this};
 };
 
diff --git a/chrome/browser/ui/views/read_later/read_later_button.h b/chrome/browser/ui/views/read_later/read_later_button.h
index 4bb20ade..fe3df854 100644
--- a/chrome/browser/ui/views/read_later/read_later_button.h
+++ b/chrome/browser/ui/views/read_later/read_later_button.h
@@ -12,6 +12,7 @@
 
 // Button in the bookmarks bar that provides access to the corresponding
 // read later menu.
+// TODO(corising): Handle the the async presentation of the UI bubble.
 class ReadLaterButton : public ToolbarButton {
  public:
   explicit ReadLaterButton(Browser* browser);
diff --git a/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc b/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
index e3f70cb..234cb7a 100644
--- a/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
+++ b/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
@@ -400,10 +400,7 @@
     LOG(ERROR) << "RenderViewContextMenuViews::Show, couldn't find WebContents";
     return NULL;
   }
-  return web_contents->GetFullscreenRenderWidgetHostView()
-             ? web_contents->GetFullscreenRenderWidgetHostView()
-                   ->GetNativeView()
-             : web_contents->GetNativeView();
+  return web_contents->GetNativeView();
 }
 
 void RenderViewContextMenuViews::OnSubmenuViewBoundsChanged(
diff --git a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.cc b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.cc
index 2848278..78b395d 100644
--- a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.cc
+++ b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.cc
@@ -86,9 +86,7 @@
 }
 
 gfx::NativeView ChromeWebContentsViewFocusHelper::GetActiveNativeView() {
-  return web_contents_->GetFullscreenRenderWidgetHostView() ?
-      web_contents_->GetFullscreenRenderWidgetHostView()->GetNativeView() :
-      web_contents_->GetNativeView();
+  return web_contents_->GetNativeView();
 }
 
 views::Widget* ChromeWebContentsViewFocusHelper::GetTopLevelWidget() {
diff --git a/chrome/browser/ui/views/tab_search/tab_search_bubble_view_browsertest.cc b/chrome/browser/ui/views/tab_search/tab_search_bubble_view_browsertest.cc
index a51c470..e22baa3 100644
--- a/chrome/browser/ui/views/tab_search/tab_search_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/tab_search/tab_search_bubble_view_browsertest.cc
@@ -65,10 +65,7 @@
 class TabSearchBubbleBrowserUITest : public DialogBrowserTest {
  public:
   TabSearchBubbleBrowserUITest() {
-    feature_list_.InitWithFeatures(
-        /*enabled_features=*/{features::kTabSearch,
-                              features::kTabSearchFixedEntrypoint},
-        /*disabled_features=*/{});
+    feature_list_.InitAndEnableFeature(features::kTabSearch);
   }
   TabSearchBubbleBrowserUITest(TabSearchBubbleBrowserUITest&) = delete;
   TabSearchBubbleBrowserUITest& operator=(TabSearchBubbleBrowserUITest&) =
diff --git a/chrome/browser/ui/views/tabs/tab_search_button.cc b/chrome/browser/ui/views/tabs/tab_search_button.cc
index f3271af..044f356 100644
--- a/chrome/browser/ui/views/tabs/tab_search_button.cc
+++ b/chrome/browser/ui/views/tabs/tab_search_button.cc
@@ -58,7 +58,6 @@
   observed_bubble_widget_.Remove(bubble_);
   bubble_ = nullptr;
   pressed_lock_.reset();
-  tab_strip()->OnTabSearchBubbleClosed();
 }
 
 bool TabSearchButton::ShowTabSearchBubble() {
diff --git a/chrome/browser/ui/views/tabs/tab_search_button_browsertest.cc b/chrome/browser/ui/views/tabs/tab_search_button_browsertest.cc
index 885d484..93a96685 100644
--- a/chrome/browser/ui/views/tabs/tab_search_button_browsertest.cc
+++ b/chrome/browser/ui/views/tabs/tab_search_button_browsertest.cc
@@ -25,22 +25,11 @@
 }
 }  // namespace
 
-class TabSearchButtonBrowserTest : public InProcessBrowserTest,
-                                   public ::testing::WithParamInterface<bool> {
+class TabSearchButtonBrowserTest : public InProcessBrowserTest {
  public:
   // InProcessBrowserTest:
   void SetUp() override {
-    // Run the test with both kTabSearchFixedEntrypoint enabled and disabled.
-    if (GetParam()) {
-      scoped_feature_list_.InitWithFeatures(
-          /*enabled_features=*/{features::kTabSearch,
-                                features::kTabSearchFixedEntrypoint},
-          /*disabled_features=*/{});
-    } else {
-      scoped_feature_list_.InitWithFeatures(
-          /*enabled_features=*/{features::kTabSearch},
-          /*disabled_features=*/{features::kTabSearchFixedEntrypoint});
-    }
+    scoped_feature_list_.InitAndEnableFeature(features::kTabSearch);
     InProcessBrowserTest::SetUp();
   }
 
@@ -56,7 +45,7 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-IN_PROC_BROWSER_TEST_P(TabSearchButtonBrowserTest, CreateAndClose) {
+IN_PROC_BROWSER_TEST_F(TabSearchButtonBrowserTest, CreateAndClose) {
   ASSERT_EQ(nullptr, tab_search_button()->bubble_for_testing());
   views::test::ButtonTestApi(tab_search_button()).NotifyClick(GetDummyEvent());
   ASSERT_NE(nullptr, tab_search_button()->bubble_for_testing());
@@ -68,7 +57,7 @@
   ASSERT_EQ(nullptr, tab_search_button()->bubble_for_testing());
 }
 
-IN_PROC_BROWSER_TEST_P(TabSearchButtonBrowserTest, TestBubbleVisible) {
+IN_PROC_BROWSER_TEST_F(TabSearchButtonBrowserTest, TestBubbleVisible) {
   EXPECT_FALSE(tab_search_button()->IsBubbleVisible());
 
   ASSERT_EQ(nullptr, tab_search_button()->bubble_for_testing());
@@ -92,7 +81,7 @@
   ASSERT_EQ(nullptr, tab_search_button()->bubble_for_testing());
 }
 
-IN_PROC_BROWSER_TEST_P(TabSearchButtonBrowserTest, BubbleNotVisibleIncognito) {
+IN_PROC_BROWSER_TEST_F(TabSearchButtonBrowserTest, BubbleNotVisibleIncognito) {
   Browser* incognito_browser = CreateIncognitoBrowser();
   BrowserView* incognito_browser_view =
       BrowserView::GetBrowserViewForBrowser(incognito_browser);
@@ -103,7 +92,7 @@
 
 // On macOS, most accelerators are handled by CommandDispatcher.
 #if !defined(OS_MAC)
-IN_PROC_BROWSER_TEST_P(TabSearchButtonBrowserTest, TestBubbleKeyboardShortcut) {
+IN_PROC_BROWSER_TEST_F(TabSearchButtonBrowserTest, TestBubbleKeyboardShortcut) {
   ASSERT_EQ(nullptr, tab_search_button()->bubble_for_testing());
 
   auto accelerator = ui::Accelerator(
@@ -120,7 +109,3 @@
   ASSERT_EQ(nullptr, tab_search_button()->bubble_for_testing());
 }
 #endif
-
-INSTANTIATE_TEST_SUITE_P(All,
-                         TabSearchButtonBrowserTest,
-                         ::testing::Values(true, false));
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index e242617..faa4045 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -39,7 +39,6 @@
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/tab_search/tab_search_bubble_view.h"
 #include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h"
 #include "chrome/browser/ui/views/tabs/new_tab_button.h"
 #include "chrome/browser/ui/views/tabs/stacked_tab_strip_layout.h"
@@ -50,7 +49,6 @@
 #include "chrome/browser/ui/views/tabs/tab_group_underline.h"
 #include "chrome/browser/ui/views/tabs/tab_group_views.h"
 #include "chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h"
-#include "chrome/browser/ui/views/tabs/tab_search_button.h"
 #include "chrome/browser/ui/views/tabs/tab_slot_view.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_layout_helper.h"
@@ -86,14 +84,12 @@
 #include "ui/gfx/skia_util.h"
 #include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/controls/image_view.h"
-#include "ui/views/layout/flex_layout.h"
 #include "ui/views/masked_targeter_delegate.h"
 #include "ui/views/mouse_watcher_view_host.h"
 #include "ui/views/rect_based_targeting_utils.h"
 #include "ui/views/view_model_utils.h"
 #include "ui/views/view_observer.h"
 #include "ui/views/view_targeter.h"
-#include "ui/views/view_targeter_delegate.h"
 #include "ui/views/view_utils.h"
 #include "ui/views/widget/root_view.h"
 #include "ui/views/widget/widget.h"
@@ -308,33 +304,6 @@
          (ui::TouchUiController::Get()->touch_ui() ? 136 : 102);
 }
 
-// |TabControlsContainer| is as a container class for control views that live
-// in the tab strip.
-class TabControlsContainer : public views::View,
-                             public views::ViewTargeterDelegate {
- public:
-  TabControlsContainer() {
-    SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
-    SetLayoutManager(std::make_unique<views::FlexLayout>());
-  }
-
-  ~TabControlsContainer() override = default;
-
-  // views::ViewTargeterDelegate:
-  bool DoesIntersectRect(const View* target,
-                         const gfx::Rect& rect) const override {
-    DCHECK_EQ(this, target);
-    const auto& children = target->children();
-    const auto hits_child = [target, rect](const views::View* child) {
-      gfx::RectF child_rect(rect);
-      views::View::ConvertRectToTarget(target, child, &child_rect);
-      return child->GetVisible() &&
-             child->HitTestRect(gfx::ToEnclosingRect(child_rect));
-    };
-    return std::any_of(children.cbegin(), children.cend(), hits_child);
-  }
-};
-
 }  // namespace
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -557,7 +526,7 @@
   }
 
   void DestroyDragController() override {
-    SetTabControlsVisible(true);
+    SetNewTabButtonVisible(true);
     drag_controller_.reset();
   }
 
@@ -748,7 +717,7 @@
 
     // Hide the new tab button immediately if we didn't originate the drag.
     if (!drag_controller_)
-      SetTabControlsVisible(false);
+      SetNewTabButtonVisible(false);
 
     // Reset dragging state of existing tabs.
     for (int i = 0; i < GetTabCount(); ++i)
@@ -782,7 +751,7 @@
     // Let the controller know that the user is not dragging this tabstrip's
     // tabs anymore.
     tab_strip_->controller_->OnStoppedDragging();
-    SetTabControlsVisible(true);
+    SetNewTabButtonVisible(true);
   }
 
   void StoppedDragging(const std::vector<TabSlotView*>& views,
@@ -792,7 +761,7 @@
     // Let the controller know that the user stopped dragging tabs.
     tab_strip_->controller_->OnStoppedDragging();
 
-    SetTabControlsVisible(true);
+    SetNewTabButtonVisible(true);
     if (move_only && tab_strip_->touch_layout_) {
       if (completed)
         tab_strip_->touch_layout_->SizeToFit();
@@ -811,7 +780,7 @@
     // Immediately hide the new tab button if the last tab is being dragged.
     const Tab* last_visible_tab = tab_strip_->GetLastVisibleTab();
     if (last_visible_tab && last_visible_tab->dragging())
-      SetTabControlsVisible(false);
+      SetNewTabButtonVisible(true);
 
     std::vector<gfx::Rect> bounds = CalculateBoundsForDraggedViews(views);
     DCHECK_EQ(views.size(), bounds.size());
@@ -854,8 +823,8 @@
     return tab_strip_->ideal_bounds(group);
   }
 
-  void SetTabControlsVisible(bool visible) {
-    tab_strip_->tab_controls_container_->SetVisible(visible);
+  void SetNewTabButtonVisible(bool visible) {
+    tab_strip_->new_tab_button_->SetVisible(visible);
   }
 
   // Used by GetInsertionIndexForDraggedBounds() when the tabstrip is stacked.
@@ -1082,8 +1051,6 @@
   RemoveMessageLoopObserver();
 
   new_tab_button_->RemoveObserver(this);
-  if (tab_search_button_)
-    tab_search_button_->RemoveObserver(this);
 
   hover_card_observer_.RemoveAll();
 
@@ -1125,8 +1092,6 @@
   for (int i = 0; i < tab_count(); ++i)
     tab_at(i)->FrameColorsChanged();
   new_tab_button_->FrameColorsChanged();
-  if (tab_search_button_)
-    tab_search_button_->FrameColorsChanged();
   UpdateContrastRatioValues();
   SchedulePaint();
 }
@@ -1165,26 +1130,22 @@
            tab_drag_handle.Intersects(rect);
   }
 
-  // Similarly, a hit in the tab controls container is considered to be in the
-  // caption if it's in this thin strip.
-  gfx::Rect tab_controls_drag_handle =
-      tab_controls_container_->GetMirroredBounds();
-  tab_controls_drag_handle.set_height(drag_handle_extension);
-  if (extend_drag_handle && tab_controls_drag_handle.Intersects(rect))
+  // Similarly, a hit in the new tab button is considered to be in the caption
+  // if it's in this thin strip.
+  gfx::Rect new_tab_button_drag_handle = new_tab_button_->GetMirroredBounds();
+  new_tab_button_drag_handle.set_height(drag_handle_extension);
+  if (extend_drag_handle && new_tab_button_drag_handle.Intersects(rect))
     return true;
 
-  // Check to see if the rect intersects the non-button parts of the tab
-  // controls container. The enclosed buttons have a non-rectangular shape, so
-  // if it's not in the visual portions of the buttons we treat it as a click to
-  // the caption.
-  gfx::RectF rect_in_tab_controls_coords_f(rect);
-  View::ConvertRectToTarget(this, tab_controls_container_,
-                            &rect_in_tab_controls_coords_f);
-  gfx::Rect rect_in_tab_controls_coords =
-      gfx::ToEnclosingRect(rect_in_tab_controls_coords_f);
-  return tab_controls_container_->GetLocalBounds().Intersects(
-             rect_in_tab_controls_coords) &&
-         !tab_controls_container_->HitTestRect(rect_in_tab_controls_coords);
+  // Check to see if the rect intersects the non-button parts of the new tab
+  // button. The button has a non-rectangular shape, so if it's not in the
+  // visual portions of the button we treat it as a click to the caption.
+  gfx::RectF rect_in_new_tab_coords_f(rect);
+  View::ConvertRectToTarget(this, new_tab_button_, &rect_in_new_tab_coords_f);
+  gfx::Rect rect_in_new_tab_coords =
+      gfx::ToEnclosingRect(rect_in_new_tab_coords_f);
+  return new_tab_button_->GetLocalBounds().Intersects(rect_in_new_tab_coords) &&
+         !new_tab_button_->HitTestRect(rect_in_new_tab_coords);
 }
 
 bool TabStrip::IsPositionInWindowCaption(const gfx::Point& point) {
@@ -1332,7 +1293,7 @@
   StartMoveTabAnimation();
   if (TabDragController::IsAttachedTo(GetDragContext()) &&
       (last_tab != GetLastVisibleTab() || last_tab->dragging())) {
-    tab_controls_container_->SetVisible(false);
+    new_tab_button_->SetVisible(false);
   }
   SwapLayoutIfNecessary();
 
@@ -1512,11 +1473,6 @@
   ShiftGroupRelative(group, 1);
 }
 
-void TabStrip::OnTabSearchBubbleClosed() {
-  UpdateIdealBounds();
-  AnimateToIdealBounds();
-}
-
 bool TabStrip::ShouldTabBeVisible(const Tab* tab) const {
   // Detached tabs should always be invisible (as they close).
   if (tab->detached())
@@ -1949,11 +1905,8 @@
 }
 
 bool TabStrip::IsFocusInTabs() const {
-  // Focus is in tabs if the currently focused view is contained in the TabStrip
-  // and not in the |tab_controls_container_|.
   return GetFocusManager() && Contains(GetFocusManager()->GetFocusedView()) &&
-         !tab_controls_container_->Contains(
-             GetFocusManager()->GetFocusedView());
+         GetFocusManager()->GetFocusedView() != new_tab_button_;
 }
 
 void TabStrip::MaybeStartDrag(
@@ -2248,14 +2201,6 @@
     SetTabSlotVisibility();
   }
 
-  if (tab_search_button_ &&
-      !tab_controls_container_->Contains(tab_search_button_)) {
-    auto preferred_size = tab_search_button_->GetPreferredSize();
-    tab_search_button_->SetBoundsRect(
-        gfx::Rect(width() - preferred_size.width(), 0, preferred_size.width(),
-                  preferred_size.height()));
-  }
-
   // Only do a layout if our size or the available width changed.
   const int available_width = GetAvailableWidthForTabStrip();
   if (last_layout_size_ == size() && last_available_width_ == available_width)
@@ -2363,8 +2308,7 @@
   if (active_tab && !is_dragging)
     active_tab->Paint(paint_info);
 
-  // Paint the tab controls.
-  tab_controls_container_->Paint(paint_info);
+  new_tab_button_->Paint(paint_info);
 
   // If dragging a group, paint the group highlight and header above all
   // non-dragging tabs and groups.
@@ -2433,9 +2377,9 @@
     if (tab)
       return tab;
   } else {
-    if (tab_controls_container_->GetVisible()) {
-      views::View* view = ConvertPointToViewAndGetTooltipHandler(
-          this, tab_controls_container_, point);
+    if (new_tab_button_->GetVisible()) {
+      views::View* view =
+          ConvertPointToViewAndGetTooltipHandler(this, new_tab_button_, point);
       if (view)
         return view;
     }
@@ -2495,43 +2439,20 @@
   // So we get enter/exit on children to switch stacked layout on and off.
   SetNotifyEnterExitOnChild(true);
 
-  tab_controls_container_ =
-      AddChildView(std::make_unique<TabControlsContainer>());
-
-  auto new_tab_button = std::make_unique<NewTabButton>(
+  new_tab_button_ = AddChildView(std::make_unique<NewTabButton>(
       this, base::BindRepeating(&TabStrip::NewTabButtonPressed,
-                                base::Unretained(this)));
-  new_tab_button->SetTooltipText(
+                                base::Unretained(this))));
+  new_tab_button_->SetTooltipText(
       l10n_util::GetStringUTF16(IDS_TOOLTIP_NEW_TAB));
-  new_tab_button->SetAccessibleName(
+  new_tab_button_->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_ACCNAME_NEWTAB));
-  new_tab_button->SetImageVerticalAlignment(views::ImageButton::ALIGN_BOTTOM);
-  new_tab_button->SetEventTargeter(
-      std::make_unique<views::ViewTargeter>(new_tab_button.get()));
-  new_tab_button->AddObserver(this);
-
-  new_tab_button_ =
-      tab_controls_container_->AddChildView(std::move(new_tab_button));
-
-  if (base::FeatureList::IsEnabled(features::kTabSearch) &&
-      !base::FeatureList::IsEnabled(features::kTabSearchFixedEntrypoint) &&
-      !controller_->GetProfile()->IsIncognitoProfile()) {
-    auto tab_search_button = std::make_unique<TabSearchButton>(this);
-    tab_search_button->SetTooltipText(
-        l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_SEARCH));
-    tab_search_button->SetAccessibleName(
-        l10n_util::GetStringUTF16(IDS_ACCNAME_TAB_SEARCH));
-    tab_search_button->SetEventTargeter(
-        std::make_unique<views::ViewTargeter>(tab_search_button.get()));
-    tab_search_button->AddObserver(this);
-
-    tab_search_button_ =
-        tab_controls_container_->AddChildView(std::move(tab_search_button));
-  }
+  new_tab_button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_BOTTOM);
+  new_tab_button_->SetEventTargeter(
+      std::make_unique<views::ViewTargeter>(new_tab_button_));
+  new_tab_button_->AddObserver(this);
 
   UpdateNewTabButtonBorder();
-  tab_controls_container_ideal_bounds_.set_size(
-      tab_controls_container_->GetPreferredSize());
+  new_tab_button_ideal_bounds_.set_size(new_tab_button_->GetPreferredSize());
 
   if (g_drop_indicator_width == 0) {
     // Direction doesn't matter, both images are the same size.
@@ -2700,12 +2621,11 @@
   // sense to me.  Why is each condition justified?
   if ((touch_layout_ || !in_tab_close_ || model_index == GetModelCount()) &&
       TabDragController::IsAttachedTo(GetDragContext())) {
-    // Don't animate the tab controls container when dragging tabs. Otherwise it
-    // looks like the controls magically appear from beyond the end of the tab
+    // Don't animate the new tab button when dragging tabs. Otherwise it looks
+    // like the new tab button magically appears from beyond the end of the tab
     // strip.
-    bounds_animator_.StopAnimatingView(tab_controls_container_);
-    tab_controls_container_->SetBoundsRect(
-        tab_controls_container_ideal_bounds_);
+    bounds_animator_.StopAnimatingView(new_tab_button_);
+    new_tab_button_->SetBoundsRect(new_tab_button_ideal_bounds_);
   }
 }
 
@@ -2761,10 +2681,10 @@
                                 base::Unretained(this))));
   }
 
-  if (bounds_animator_.GetTargetBounds(tab_controls_container_) !=
-      tab_controls_container_ideal_bounds_) {
-    bounds_animator_.AnimateViewTo(tab_controls_container_,
-                                   tab_controls_container_ideal_bounds_);
+  if (bounds_animator_.GetTargetBounds(new_tab_button_) !=
+      new_tab_button_ideal_bounds_) {
+    bounds_animator_.AnimateViewTo(new_tab_button_,
+                                   new_tab_button_ideal_bounds_);
   }
 }
 
@@ -2778,7 +2698,7 @@
     header_pair.second->UpdateBounds();
   }
 
-  tab_controls_container_->SetBoundsRect(tab_controls_container_ideal_bounds_);
+  new_tab_button_->SetBoundsRect(new_tab_button_ideal_bounds_);
 
   PreferredSizeChanged();
 }
@@ -2803,7 +2723,7 @@
   // The grab area is adjacent to the new tab button.  Treat the padding in the
   // new tab button as part of the grab area.
   constexpr int kApparentWidth = 50;
-  return kApparentWidth - tab_controls_container_->GetInsets().right();
+  return kApparentWidth - new_tab_button_->GetInsets().right();
 }
 
 bool TabStrip::TitlebarBackgroundIsTransparent() const {
@@ -2876,8 +2796,8 @@
 }
 
 int TabStrip::GetRightSideReservedWidth() const {
-  return tab_controls_container_ideal_bounds_.width() +
-         TabToNewTabButtonSpacing() + FrameGrabWidth();
+  return new_tab_button_ideal_bounds_.width() + TabToNewTabButtonSpacing() +
+         FrameGrabWidth();
 }
 
 const Tab* TabStrip::GetLastVisibleTab() const {
@@ -3461,7 +3381,7 @@
 
   if (touch_layout_) {
     const int trailing_x = tabs_.ideal_bounds(tab_count() - 1).right();
-    tab_controls_container_ideal_bounds_.set_origin(
+    new_tab_button_ideal_bounds_.set_origin(
         gfx::Point(trailing_x + TabToNewTabButtonSpacing(), 0));
   } else {
     const int available_width_for_tabs = CalculateAvailableWidthForTabs();
@@ -3472,13 +3392,9 @@
         base::FeatureList::IsEnabled(features::kScrollableTabStrip)
             ? trailing_x
             : std::min(available_width_for_tabs, trailing_x);
-    // We want to lock the |tab_controls_container_| in place if the Tab Search
-    // bubble is open to prevent the UI sliding across the screen as the tab
-    // strip changes.
-    if (!tab_search_button_ || !tab_search_button_->IsBubbleVisible()) {
-      tab_controls_container_ideal_bounds_.set_origin(
-          gfx::Point(ntb_x_offset + TabToNewTabButtonSpacing(), 0));
-    }
+
+    new_tab_button_ideal_bounds_.set_origin(
+        gfx::Point(ntb_x_offset + TabToNewTabButtonSpacing(), 0));
   }
 }
 
@@ -3670,24 +3586,17 @@
 }
 
 void TabStrip::UpdateNewTabButtonBorder() {
-  // The controls container is placed vertically exactly in the center of the
-  // tabstrip.
   const int extra_vertical_space = GetLayoutConstant(TAB_HEIGHT) -
                                    GetLayoutConstant(TABSTRIP_TOOLBAR_OVERLAP) -
                                    NewTabButton::kButtonSize.height();
-
-  // Extend the border of the tab controls such that it extends to the top of
-  // the tabstrip bounds. This is essential to ensure they targetable on the
-  // edge of the screen when in fullscreen mode and ensures the buttons abide by
-  // the correct Fitt's Law behavior (https://crbug.com/1136557).
-  const gfx::Insets button_insets(extra_vertical_space / 2, 0, 0, 0);
-  new_tab_button_->SetBorder(views::CreateEmptyBorder(button_insets));
-  if (tab_search_button_)
-    tab_search_button_->SetBorder(views::CreateEmptyBorder(button_insets));
-
   constexpr int kHorizontalInset = 8;
-  tab_controls_container_->SetBorder(views::CreateEmptyBorder(
-      gfx::Insets(0, kHorizontalInset, 0, kHorizontalInset)));
+  // The new tab button is placed vertically exactly in the center of the
+  // tabstrip. Extend the border of the button such that it extends to the top
+  // of the tabstrip bounds. This is essential to ensure it is targetable on the
+  // edge of the screen when in fullscreen mode and ensures the  button abides
+  // by the correct Fitt's Law behavior (https://crbug.com/1136557).
+  new_tab_button_->SetBorder(views::CreateEmptyBorder(gfx::Insets(
+      extra_vertical_space / 2, kHorizontalInset, 0, kHorizontalInset)));
 }
 
 void TabStrip::OnTabSlotAnimationProgressed(TabSlotView* view) {
@@ -3822,9 +3731,9 @@
     if (tab)
       return tab;
   } else {
-    if (tab_controls_container_->GetVisible()) {
-      views::View* view = ConvertPointToViewAndGetEventHandler(
-          this, tab_controls_container_, point);
+    if (new_tab_button_->GetVisible()) {
+      views::View* view =
+          ConvertPointToViewAndGetEventHandler(this, new_tab_button_, point);
       if (view)
         return view;
     }
@@ -3857,9 +3766,8 @@
 
 void TabStrip::OnTouchUiChanged() {
   UpdateNewTabButtonBorder();
-  tab_controls_container_ideal_bounds_.set_size(
-      tab_controls_container_->GetPreferredSize());
-  tab_controls_container_->SetBoundsRect(tab_controls_container_ideal_bounds_);
+  new_tab_button_ideal_bounds_.set_size(new_tab_button_->GetPreferredSize());
+  new_tab_button_->SetBoundsRect(new_tab_button_ideal_bounds_);
   StopAnimating(true);
   PreferredSizeChanged();
 }
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index 7c57814..60d266e 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -44,7 +44,6 @@
 class StackedTabStripLayout;
 class Tab;
 class TabHoverCardBubbleView;
-class TabSearchButton;
 class TabStripController;
 class TabStripObserver;
 class TabStripLayoutHelper;
@@ -146,9 +145,9 @@
   // Sets |stacked_layout_| and animates if necessary.
   void SetStackedLayout(bool stacked_layout);
 
-  // Returns the ideal bounds of the tab controls container.
-  gfx::Rect tab_controls_container_ideal_bounds() const {
-    return tab_controls_container_ideal_bounds_;
+  // Returns the ideal bounds of the new tab button.
+  const gfx::Rect& new_tab_button_ideal_bounds() const {
+    return new_tab_button_ideal_bounds_;
   }
 
   // Adds a tab at the specified index.
@@ -205,12 +204,6 @@
   // Attempts to move the specified group to the right.
   void ShiftGroupRight(const tab_groups::TabGroupId& group);
 
-  // While the Tab Search bubble is open, the |tab_controls_container_| is kept
-  // in a fixed position in the tab strip. This is called when the bubble is
-  // closed to allow the |tab_controls_container_| to animate to the correct
-  // position.
-  void OnTabSearchBubbleClosed();
-
   // Returns true if the tab is not partly or fully clipped (due to overflow),
   // and the tab couldn't become partly clipped due to changing the selected tab
   // (for example, if currently the strip has the last tab selected, and
@@ -247,9 +240,6 @@
   // Returns the NewTabButton.
   NewTabButton* new_tab_button() { return new_tab_button_; }
 
-  // Returns the TabSearchButton.
-  TabSearchButton* tab_search_button() { return tab_search_button_; }
-
   // Returns the index of the specified view in the model coordinate system, or
   // -1 if view is closing or not a tab.
   int GetModelIndexOf(const TabSlotView* view) const;
@@ -709,15 +699,11 @@
   // Responsible for animating tabs in response to model changes.
   views::BoundsAnimator bounds_animator_{this};
 
-  // Container that holds the |new_tab_button_| and the |tab_search_button_|.
-  views::View* tab_controls_container_ = nullptr;
+  // The "New Tab" button.
   NewTabButton* new_tab_button_ = nullptr;
-  // |tab_search_button_| will be null if features::kTabSearch is disabled or if
-  // the current profile is an incognito profile.
-  TabSearchButton* tab_search_button_ = nullptr;
 
-  // Ideal bounds of container holding the tab controls.
-  gfx::Rect tab_controls_container_ideal_bounds_;
+  // Ideal bounds of the new tab button.
+  gfx::Rect new_tab_button_ideal_bounds_;
 
   // If this value is defined, it is used as the width to lay out tabs
   // (instead of GetTabAreaWidth()). It is defined when closing tabs with the
diff --git a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
index 69757df..5699f316 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
@@ -138,10 +138,6 @@
     return tab->icon_->ShowingAttentionIndicator();
   }
 
-  views::View* tab_controls_container() {
-    return tab_strip_->tab_controls_container_;
-  }
-
   // Checks whether |tab| contains |point_in_tabstrip_coords|, where the point
   // is in |tab_strip_| coordinates.
   bool IsPointInTab(Tab* tab, const gfx::Point& point_in_tabstrip_coords) {
@@ -863,8 +859,7 @@
 
   CompleteAnimationAndLayout();
 
-  EXPECT_LE(tab_strip_->tab_controls_container_ideal_bounds().right(),
-            kTabStripWidth);
+  EXPECT_LE(tab_strip_->new_tab_button_ideal_bounds().right(), kTabStripWidth);
 }
 
 TEST_P(TabStripTest, NewTabButtonRightOfTabs) {
@@ -875,7 +870,7 @@
 
   AnimateToIdealBounds();
 
-  EXPECT_EQ(tab_strip_->tab_controls_container_ideal_bounds().x(),
+  EXPECT_EQ(tab_strip_->new_tab_button_ideal_bounds().x(),
             tab_strip_->ideal_bounds(0).right() + TabToNewTabButtonSpacing());
 }
 
@@ -1351,20 +1346,10 @@
 
   AnimateToIdealBounds();
 
-  // |tab_controls_container_| should sit flush with the top of the tab strip.
-  EXPECT_EQ(0, tab_strip_->tab_controls_container_ideal_bounds().y());
-
   // The new tab button should sit flush with the top of the
-  // |tab_controls_container_|.
+  // |tab_strip_|.
+  EXPECT_EQ(tab_strip_, tab_strip_->new_tab_button()->parent());
   EXPECT_EQ(0, tab_strip_->new_tab_button()->bounds().y());
-
-  // The new tab button should be positioned flush with the top of the tab
-  // strip.
-  gfx::RectF ntb_in_child_coords_f(tab_strip_->new_tab_button()->bounds());
-  views::View::ConvertRectToTarget(tab_controls_container(), tab_strip_,
-                                   &ntb_in_child_coords_f);
-  gfx::Rect ntb_in_child_coords = gfx::ToEnclosingRect(ntb_in_child_coords_f);
-  EXPECT_EQ(0, ntb_in_child_coords.y());
 }
 
 INSTANTIATE_TEST_SUITE_P(All, TabStripTest, ::testing::Values(false, true));
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index e53282f..209dc74 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -153,6 +153,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "base/system/sys_info.h"
+#include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/device_sync/device_sync_client_factory.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_factory.h"
@@ -167,6 +168,7 @@
 #include "chrome/browser/chromeos/web_applications/chrome_media_app_ui_delegate.h"
 #include "chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_ui.h"
 #include "chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.h"
+#include "chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.h"
 #include "chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h"
 #include "chrome/browser/ui/webui/chromeos/bluetooth_pairing_dialog.h"
 #include "chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_dialog.h"
@@ -730,12 +732,19 @@
     if (url.host_piece() == chrome::kChromeUINearbyInternalsHost)
       return &NewWebUI<NearbyInternalsUI>;
   }
-  if (url.host_piece() == chrome::kChromeUIArcGraphicsTracingHost)
-    return &NewWebUI<chromeos::ArcGraphicsTracingUI<
-        chromeos::ArcGraphicsTracingMode::kFull>>;
-  if (url.host_piece() == chrome::kChromeUIArcOverviewTracingHost)
-    return &NewWebUI<chromeos::ArcGraphicsTracingUI<
-        chromeos::ArcGraphicsTracingMode::kOverview>>;
+  if (arc::IsArcAllowedForProfile(profile)) {
+    if (url.host_piece() == chrome::kChromeUIArcGraphicsTracingHost) {
+      return &NewWebUI<chromeos::ArcGraphicsTracingUI<
+          chromeos::ArcGraphicsTracingMode::kFull>>;
+    }
+    if (url.host_piece() == chrome::kChromeUIArcOverviewTracingHost) {
+      return &NewWebUI<chromeos::ArcGraphicsTracingUI<
+          chromeos::ArcGraphicsTracingMode::kOverview>>;
+    }
+    if (url.host_piece() == chrome::kChromeUIArcPowerControlHost) {
+      return &NewWebUI<chromeos::ArcPowerControlUI>;
+    }
+  }
 
 #if !defined(OFFICIAL_BUILD)
 #if !defined(USE_REAL_DBUS_CLIENTS)
diff --git a/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.cc b/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.cc
new file mode 100644
index 0000000..21390425
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.cc
@@ -0,0 +1,393 @@
+// 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 "chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.h"
+
+#include "base/bind.h"
+#include "base/linux_util.h"
+#include "base/process/launch.h"
+#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
+#include "base/trace_event/trace_event.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/arc/instance_throttle/arc_instance_throttle.h"
+#include "chrome/browser/chromeos/arc/tracing/arc_system_stat_collector.h"
+#include "chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.h"
+#include "chrome/browser/chromeos/arc/tracing/arc_tracing_model.h"
+#include "chrome/browser/chromeos/arc/tracing/arc_value_event_trimmer.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "components/arc/arc_service_manager.h"
+#include "components/arc/mojom/power.mojom.h"
+#include "components/arc/session/arc_bridge_service.h"
+
+namespace chromeos {
+
+namespace {
+
+// Maximum interval to display in tracing.
+constexpr base::TimeDelta kMaxIntervalToDisplay =
+    base::TimeDelta::FromMinutes(5);
+
+// Names of throttling mode.
+constexpr char kThrottlingDisable[] = "disable";
+constexpr char kThrottlingAuto[] = "auto";
+constexpr char kThrottlingForce[] = "force";
+
+// Names of wakenessfull mode.
+constexpr char kWakenessfullWakeUp[] = "wakeup";
+constexpr char kWakenessfullDoze[] = "doze";
+constexpr char kWakenessfullSleep[] = "sleep";
+
+// To read developer mode.
+constexpr const char kCrosSystemPath[] = "/usr/bin/crossystem";
+constexpr const char kCrosDebug[] = "cros_debug";
+
+void OnAndroidSuspendReady() {}
+
+std::string GetJavascriptDomain() {
+  return "cr.ArcPowerControl.";
+}
+
+bool IsDeveloperMode() {
+  std::string output;
+  if (!base::GetAppOutput({kCrosSystemPath, kCrosDebug}, &output)) {
+    LOG(ERROR) << "Failed to read property " << kCrosDebug;
+    return false;
+  }
+
+  return output == "1";
+}
+
+base::Value BuildTracingModel(
+    base::Time timestamp,
+    base::TimeTicks time_min,
+    base::TimeTicks time_max,
+    std::unique_ptr<arc::ArcSystemStatCollector> system_stat_collector,
+    ArcPowerControlHandler::WakefulnessModeEvents wakefulness_mode_events,
+    ArcPowerControlHandler::ThrottlingEvents throttling_events) {
+  DCHECK(system_stat_collector);
+
+  arc::ArcTracingModel common_model;
+  const base::TimeTicks time_min_clamped =
+      std::max(time_min, time_max - system_stat_collector->max_interval());
+  common_model.SetMinMaxTime(
+      (time_min_clamped - base::TimeTicks()).InMicroseconds(),
+      (time_max - base::TimeTicks()).InMicroseconds());
+
+  arc::ArcValueEventTrimmer wakenessfull_mode(
+      &common_model.system_model().memory_events(),
+      arc::ArcValueEvent::Type::kWakenessfullMode);
+  for (const auto& wakefulness_mode_event : wakefulness_mode_events) {
+    const int64_t timestamp =
+        (wakefulness_mode_event.first - base::TimeTicks()).InMicroseconds();
+    wakenessfull_mode.MaybeAdd(timestamp,
+                               static_cast<int>(wakefulness_mode_event.second));
+  }
+  arc::ArcValueEventTrimmer throttling(
+      &common_model.system_model().memory_events(),
+      arc::ArcValueEvent::Type::kThrottlingMode);
+  for (const auto& throttling_event : throttling_events) {
+    const int64_t timestamp =
+        (throttling_event.first - base::TimeTicks()).InMicroseconds();
+    throttling.MaybeAdd(timestamp, static_cast<int>(throttling_event.second));
+  }
+
+  // Flush automatically normalizes the model.
+  system_stat_collector->Flush(time_min, time_max,
+                               &common_model.system_model());
+
+  arc::ArcTracingGraphicsModel graphics_model;
+  graphics_model.set_skip_structure_validation();
+  graphics_model.set_platform(base::GetLinuxDistro());
+  graphics_model.set_timestamp(timestamp);
+  graphics_model.Build(common_model);
+
+  return std::move(*graphics_model.Serialize());
+}
+
+}  // namespace
+
+ArcPowerControlHandler::ArcPowerControlHandler()
+    : power_bridge_(arc::ArcPowerBridge::GetForBrowserContext(
+          ProfileManager::GetActiveUserProfile())),
+      instance_throttle_(arc::ArcInstanceThrottle::GetForBrowserContext(
+          ProfileManager::GetActiveUserProfile())) {
+  DCHECK(power_bridge_);
+  DCHECK(instance_throttle_);
+  power_bridge_->AddObserver(this);
+  instance_throttle_->AddServiceObserver(this);
+}
+
+ArcPowerControlHandler::~ArcPowerControlHandler() {
+  instance_throttle_->RemoveServiceObserver(this);
+  power_bridge_->RemoveObserver(this);
+}
+
+void ArcPowerControlHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "ready", base::BindRepeating(&ArcPowerControlHandler::HandleReady,
+                                   base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "setWakefulnessMode",
+      base::BindRepeating(&ArcPowerControlHandler::HandleSetWakefulnessMode,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "setThrottling",
+      base::BindRepeating(&ArcPowerControlHandler::HandleSetThrottling,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "startTracing",
+      base::BindRepeating(&ArcPowerControlHandler::HandleStartTracing,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "stopTracing",
+      base::BindRepeating(&ArcPowerControlHandler::HandleStopTracing,
+                          base::Unretained(this)));
+}
+
+void ArcPowerControlHandler::OnWakefulnessChanged(
+    arc::mojom::WakefulnessMode mode) {
+  wakefulness_mode_ = mode;
+  UpdatePowerControlStatus();
+
+  if (stop_tracing_timer_.IsRunning()) {
+    wakefulness_mode_events_.emplace_back(
+        std::make_pair(TRACE_TIME_TICKS_NOW(), wakefulness_mode_));
+  }
+}
+
+void ArcPowerControlHandler::OnThrottle(ThrottleObserver::PriorityLevel level) {
+  UpdatePowerControlStatus();
+
+  std::string mode;
+  switch (instance_throttle_->enforced_level()) {
+    case ThrottleObserver::PriorityLevel::UNKNOWN:
+      mode = kThrottlingAuto;
+      break;
+    case ThrottleObserver::PriorityLevel::LOW:
+      mode = kThrottlingForce;
+      break;
+    default:
+      mode = kThrottlingDisable;
+      break;
+  }
+
+  CallJavascriptFunction(GetJavascriptDomain() + "setThrottlingMode",
+                         base::Value(mode));
+
+  if (stop_tracing_timer_.IsRunning()) {
+    throttling_events_.emplace_back(
+        std::make_pair(TRACE_TIME_TICKS_NOW(), level));
+  }
+}
+
+void ArcPowerControlHandler::HandleReady(const base::ListValue* args) {
+  arc::mojom::PowerInstance* power_instance = ARC_GET_INSTANCE_FOR_METHOD(
+      arc::ArcServiceManager::Get()->arc_bridge_service()->power(),
+      GetWakefulnessMode);
+  if (!power_instance)
+    return;
+
+  power_instance->GetWakefulnessMode(
+      base::BindOnce(&ArcPowerControlHandler::OnWakefulnessChanged,
+                     weak_ptr_factory_.GetWeakPtr()));
+
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
+      base::BindOnce(&IsDeveloperMode),
+      base::BindOnce(&ArcPowerControlHandler::OnIsDeveloperMode,
+                     weak_ptr_factory_.GetWeakPtr()));
+
+  OnThrottle(instance_throttle_->level());
+}
+
+void ArcPowerControlHandler::HandleSetWakefulnessMode(
+    const base::ListValue* args) {
+  DCHECK_EQ(1U, args->GetSize());
+
+  if (!power_control_enabled_) {
+    LOG(ERROR) << "Power control is not enabled";
+    return;
+  }
+
+  if (!args->GetList()[0].is_string()) {
+    LOG(ERROR) << "Invalid input";
+    return;
+  }
+
+  auto* const power =
+      arc::ArcServiceManager::Get()->arc_bridge_service()->power();
+  DCHECK(power);
+
+  const std::string mode = args->GetList()[0].GetString();
+  if (mode == kWakenessfullWakeUp) {
+    if (wakefulness_mode_ == arc::mojom::WakefulnessMode::ASLEEP) {
+      arc::mojom::PowerInstance* const power_instance =
+          ARC_GET_INSTANCE_FOR_METHOD(power, Resume);
+      if (power_instance)
+        power_instance->Resume();
+    } else {
+      arc::mojom::PowerInstance* const power_instance =
+          ARC_GET_INSTANCE_FOR_METHOD(power, SetInteractive);
+      if (power_instance)
+        power_instance->SetInteractive(true);
+    }
+  } else if (mode == kWakenessfullDoze) {
+    arc::mojom::PowerInstance* const power_instance =
+        ARC_GET_INSTANCE_FOR_METHOD(power, SetInteractive);
+    if (power_instance)
+      power_instance->SetInteractive(false);
+  } else if (mode == kWakenessfullSleep) {
+    arc::mojom::PowerInstance* const power_instance =
+        ARC_GET_INSTANCE_FOR_METHOD(power, Suspend);
+    if (power_instance)
+      power_instance->Suspend(base::BindOnce(&OnAndroidSuspendReady));
+  } else {
+    LOG(ERROR) << "Invalid mode: " << mode;
+  }
+}
+
+void ArcPowerControlHandler::HandleSetThrottling(const base::ListValue* args) {
+  DCHECK_EQ(1U, args->GetSize());
+
+  if (!power_control_enabled_) {
+    LOG(ERROR) << "Power control is not enabled";
+    return;
+  }
+
+  if (!args->GetList()[0].is_string()) {
+    LOG(ERROR) << "Invalid input";
+    return;
+  }
+
+  ThrottleObserver::PriorityLevel enforced_level;
+  const std::string mode = args->GetList()[0].GetString();
+  if (mode == kThrottlingDisable) {
+    enforced_level = ThrottleObserver::PriorityLevel::CRITICAL;
+  } else if (mode == kThrottlingAuto) {
+    enforced_level = ThrottleObserver::PriorityLevel::UNKNOWN;
+  } else if (mode == kThrottlingForce) {
+    enforced_level = ThrottleObserver::PriorityLevel::LOW;
+  } else {
+    LOG(ERROR) << "Invalid mode: " << mode;
+    return;
+  }
+
+  instance_throttle_->SetEnforced(enforced_level);
+}
+
+void ArcPowerControlHandler::HandleStartTracing(const base::ListValue* args) {
+  DCHECK(!args->GetSize());
+  StartTracing();
+}
+
+void ArcPowerControlHandler::HandleStopTracing(const base::ListValue* args) {
+  DCHECK(!args->GetSize());
+  StopTracing();
+}
+
+void ArcPowerControlHandler::StartTracing() {
+  SetTracingStatus("Collecting samples...");
+
+  timestamp_ = base::Time::Now();
+  tracing_time_min_ = TRACE_TIME_TICKS_NOW();
+
+  wakefulness_mode_events_.clear();
+  wakefulness_mode_events_.emplace_back(
+      std::make_pair(tracing_time_min_, wakefulness_mode_));
+  throttling_events_.clear();
+  throttling_events_.emplace_back(
+      std::make_pair(tracing_time_min_, instance_throttle_->level()));
+  system_stat_colletor_ = std::make_unique<arc::ArcSystemStatCollector>();
+  system_stat_colletor_->Start(kMaxIntervalToDisplay);
+  stop_tracing_timer_.Start(FROM_HERE, system_stat_colletor_->max_interval(),
+                            base::BindOnce(&ArcPowerControlHandler::StopTracing,
+                                           base::Unretained(this)));
+}
+
+void ArcPowerControlHandler::StopTracing() {
+  if (!system_stat_colletor_)
+    return;
+
+  const base::TimeTicks tracing_time_max = TRACE_TIME_TICKS_NOW();
+  stop_tracing_timer_.Stop();
+  system_stat_colletor_->Stop();
+
+  SetTracingStatus("Building model...");
+
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+      base::BindOnce(&BuildTracingModel, timestamp_, tracing_time_min_,
+                     tracing_time_max, std::move(system_stat_colletor_),
+                     std::move(wakefulness_mode_events_),
+                     std::move(throttling_events_)),
+      base::BindOnce(&ArcPowerControlHandler::OnTracingModelReady,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ArcPowerControlHandler::OnTracingModelReady(base::Value result) {
+  SetTracingStatus("Tracing ready");
+
+  CallJavascriptFunction(GetJavascriptDomain() + "setModel", std::move(result));
+}
+
+void ArcPowerControlHandler::OnIsDeveloperMode(bool developer_mode) {
+  power_control_enabled_ = developer_mode;
+  CallJavascriptFunction(GetJavascriptDomain() + "setPowerControlEnabled",
+                         base::Value(power_control_enabled_));
+}
+
+void ArcPowerControlHandler::UpdatePowerControlStatus() {
+  AllowJavascript();
+
+  std::string status;
+  switch (wakefulness_mode_) {
+    case arc::mojom::WakefulnessMode::UNKNOWN:
+      status = "Unknown";
+      break;
+    case arc::mojom::WakefulnessMode::ASLEEP:
+      status = "Asleep";
+      break;
+    case arc::mojom::WakefulnessMode::AWAKE:
+      status = "Awake";
+      break;
+    case arc::mojom::WakefulnessMode::DREAMING:
+      status = "Dreaming";
+      break;
+    case arc::mojom::WakefulnessMode::DOZING:
+      status = "Dozing";
+      break;
+  }
+
+  status += " (";
+  switch (instance_throttle_->level()) {
+    case ThrottleObserver::PriorityLevel::UNKNOWN:
+      status += "throttling unknown";
+      break;
+    case ThrottleObserver::PriorityLevel::LOW:
+      status += "throttling";
+      break;
+    case ThrottleObserver::PriorityLevel::NORMAL:
+      status += "foreground";
+      break;
+    case ThrottleObserver::PriorityLevel::IMPORTANT:
+      status += "important foreground";
+      break;
+    case ThrottleObserver::PriorityLevel::CRITICAL:
+      status += "critical foreground";
+      break;
+  }
+  status += ")";
+
+  CallJavascriptFunction(GetJavascriptDomain() + "setPowerControlStatus",
+                         base::Value(status));
+}
+
+void ArcPowerControlHandler::SetTracingStatus(const std::string& status) {
+  CallJavascriptFunction(GetJavascriptDomain() + "setTracingStatus",
+                         base::Value(status));
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.h b/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.h
new file mode 100644
index 0000000..10af11c7
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.h
@@ -0,0 +1,97 @@
+// 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 CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_POWER_CONTROL_ARC_POWER_CONTROL_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_POWER_CONTROL_ARC_POWER_CONTROL_HANDLER_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/chromeos/throttle_service.h"
+#include "components/arc/mojom/power.mojom.h"
+#include "components/arc/power/arc_power_bridge.h"
+#include "content/public/browser/web_ui_message_handler.h"
+#include "ui/aura/window_observer.h"
+#include "ui/events/event_handler.h"
+#include "ui/wm/public/activation_change_observer.h"
+
+namespace arc {
+class ArcInstanceThrottle;
+class ArcSystemStatCollector;
+}  // namespace arc
+
+namespace chromeos {
+
+class ArcPowerControlHandler : public content::WebUIMessageHandler,
+                               public arc::ArcPowerBridge::Observer,
+                               public ThrottleService::ServiceObserver {
+ public:
+  using WakefulnessModeEvents =
+      std::vector<std::pair<base::TimeTicks, arc::mojom::WakefulnessMode>>;
+  using ThrottlingEvents =
+      std::vector<std::pair<base::TimeTicks, ThrottleObserver::PriorityLevel>>;
+
+  ArcPowerControlHandler();
+  ~ArcPowerControlHandler() override;
+
+  // content::WebUIMessageHandler:
+  void RegisterMessages() override;
+
+  // arc::ArcPowerBridge::Observer:
+  void OnWakefulnessChanged(arc::mojom::WakefulnessMode mode) override;
+
+  // ThrottleService::ServiceObserver:
+  void OnThrottle(ThrottleObserver::PriorityLevel level) override;
+
+ private:
+  // Handlers for calls from JS.
+  void HandleReady(const base::ListValue* args);
+  void HandleSetWakefulnessMode(const base::ListValue* args);
+  void HandleSetThrottling(const base::ListValue* args);
+  void HandleStartTracing(const base::ListValue* args);
+  void HandleStopTracing(const base::ListValue* args);
+
+  void StartTracing();
+  void StopTracing();
+  void OnTracingModelReady(base::Value result);
+
+  void UpdatePowerControlStatus();
+  void SetTracingStatus(const std::string& status);
+
+  void OnIsDeveloperMode(bool developer_mode);
+
+  // Unowned pointers.
+  arc::ArcPowerBridge* const power_bridge_;
+  arc::ArcInstanceThrottle* const instance_throttle_;
+
+  // Collects system stats runtime.
+  base::Time timestamp_;
+  base::TimeTicks tracing_time_min_;
+  base::OneShotTimer stop_tracing_timer_;
+  std::unique_ptr<arc::ArcSystemStatCollector> system_stat_colletor_;
+
+  // It collects power mode and throttling events in case tracing is active.
+  WakefulnessModeEvents wakefulness_mode_events_;
+  ThrottlingEvents throttling_events_;
+
+  // Keeps current wakefulness mode.
+  arc::mojom::WakefulnessMode wakefulness_mode_ =
+      arc::mojom::WakefulnessMode::UNKNOWN;
+
+  // Enabled in dev mode only.
+  bool power_control_enabled_ = false;
+
+  base::WeakPtrFactory<ArcPowerControlHandler> weak_ptr_factory_{this};
+
+  ArcPowerControlHandler(ArcPowerControlHandler const&) = delete;
+  ArcPowerControlHandler& operator=(ArcPowerControlHandler const&) = delete;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_POWER_CONTROL_ARC_POWER_CONTROL_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.cc b/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.cc
new file mode 100644
index 0000000..e4f85d03
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.cc
@@ -0,0 +1,61 @@
+// 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 "chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.h"
+
+#include <string>
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/browser_resources.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "services/network/public/mojom/content_security_policy.mojom.h"
+#include "ui/base/webui/web_ui_util.h"
+
+namespace {
+
+constexpr char kArcPowerControlJsPath[] = "arc_power_control.js";
+constexpr char kArcPowerControlCssPath[] = "arc_power_control.css";
+constexpr char kArcOverviewTracingUiJsPath[] = "arc_overview_tracing_ui.js";
+constexpr char kArcTracingUiJsPath[] = "arc_tracing_ui.js";
+constexpr char kArcTracingCssPath[] = "arc_tracing.css";
+
+content::WebUIDataSource* CreatePowerControlDataSource() {
+  content::WebUIDataSource* const source =
+      content::WebUIDataSource::Create(chrome::kChromeUIArcPowerControlHost);
+  source->UseStringsJs();
+  source->SetDefaultResource(IDR_ARC_POWER_CONTROL_HTML);
+  source->AddResourcePath(kArcPowerControlJsPath, IDR_ARC_POWER_CONTROL_JS);
+  source->AddResourcePath(kArcPowerControlCssPath, IDR_ARC_POWER_CONTROL_CSS);
+  source->AddResourcePath(kArcOverviewTracingUiJsPath,
+                          IDR_ARC_OVERVIEW_TRACING_UI_JS);
+  source->AddResourcePath(kArcTracingCssPath, IDR_ARC_TRACING_CSS);
+  source->AddResourcePath(kArcTracingUiJsPath, IDR_ARC_TRACING_UI_JS);
+  source->OverrideContentSecurityPolicy(
+      network::mojom::CSPDirectiveName::ScriptSrc,
+      "script-src chrome://resources 'self';");
+
+  base::DictionaryValue localized_strings;
+  const std::string& app_locale = g_browser_process->GetApplicationLocale();
+  webui::SetLoadTimeDataDefaults(app_locale, &localized_strings);
+  source->AddLocalizedStrings(localized_strings);
+
+  return source;
+}
+
+}  // anonymous namespace
+
+namespace chromeos {
+
+ArcPowerControlUI::ArcPowerControlUI(content::WebUI* web_ui)
+    : WebUIController(web_ui) {
+  web_ui->AddMessageHandler(std::make_unique<ArcPowerControlHandler>());
+  content::WebUIDataSource::Add(Profile::FromWebUI(web_ui),
+                                CreatePowerControlDataSource());
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.h b/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.h
new file mode 100644
index 0000000..a2d18e2
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.h
@@ -0,0 +1,28 @@
+// 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 CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_POWER_CONTROL_ARC_POWER_CONTROL_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_POWER_CONTROL_ARC_POWER_CONTROL_UI_H_
+
+#include "content/public/browser/web_ui_controller.h"
+
+namespace content {
+class WebUI;
+}
+
+namespace chromeos {
+
+// WebUI controller for ARC power control.
+class ArcPowerControlUI : public content::WebUIController {
+ public:
+  explicit ArcPowerControlUI(content::WebUI* web_ui);
+
+ private:
+  ArcPowerControlUI(ArcPowerControlUI const&) = delete;
+  ArcPowerControlUI& operator=(ArcPowerControlUI const&) = delete;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_POWER_CONTROL_ARC_POWER_CONTROL_UI_H_
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index fb367ef..807a019 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -72,6 +72,7 @@
 #include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.h"
 #include "chrome/browser/ui/webui/chromeos/login/packaged_license_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_fatal_error_screen_handler.h"
@@ -183,7 +184,7 @@
   source->AddResourcePath(kArcPlaystoreCSSPath, IDR_ARC_SUPPORT_PLAYSTORE_CSS);
   source->AddResourcePath(kArcPlaystoreJSPath, IDR_ARC_SUPPORT_PLAYSTORE_JS);
   source->AddResourcePath(kArcPlaystoreLogoPath,
-      IDR_ARC_SUPPORT_PLAYSTORE_LOGO);
+                          IDR_ARC_SUPPORT_PLAYSTORE_LOGO);
 
   source->AddResourcePath(kRecommendAppListViewJSPath,
                           IDR_ARC_SUPPORT_RECOMMEND_APP_LIST_VIEW_JS);
@@ -519,6 +520,9 @@
   AddScreenHandler(
       std::make_unique<TpmErrorScreenHandler>(js_calls_container_.get()));
 
+  AddScreenHandler(std::make_unique<ParentalHandoffScreenHandler>(
+      js_calls_container_.get()));
+
   Profile* profile = Profile::FromWebUI(web_ui());
   // Set up the chrome://theme/ source, for Chrome logo.
   content::URLDataSource::Add(profile, std::make_unique<ThemeSource>(profile));
diff --git a/chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.cc
new file mode 100644
index 0000000..e57488b8
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.cc
@@ -0,0 +1,64 @@
+// 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 "chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.h"
+
+#include "chrome/browser/chromeos/login/screens/parental_handoff_screen.h"
+#include "chrome/browser/ui/webui/chromeos/login/js_calls_container.h"
+#include "chrome/grit/chromium_strings.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/login/localized_values_builder.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace chromeos {
+
+namespace {
+
+constexpr char kTitle[] = "title";
+constexpr char kSubTitle[] = "subtitle";
+
+}  // namespace
+
+// static
+constexpr StaticOobeScreenId ParentalHandoffScreenView::kScreenId;
+
+ParentalHandoffScreenHandler::ParentalHandoffScreenHandler(
+    JSCallsContainer* js_calls_container)
+    : BaseScreenHandler(kScreenId, js_calls_container) {
+  set_user_acted_method_path("login.ParentalHandoffScreen.userActed");
+}
+
+ParentalHandoffScreenHandler::~ParentalHandoffScreenHandler() {
+  if (screen_)
+    screen_->OnViewDestroyed(this);
+}
+
+void ParentalHandoffScreenHandler::DeclareLocalizedValues(
+    ::login::LocalizedValuesBuilder* builder) {
+  builder->Add("parentalHandoffDialogNextButton",
+               IDS_LOGIN_PARENTAL_HANDOFF_SCREEN_NEXT_BUTTON);
+}
+
+void ParentalHandoffScreenHandler::Initialize() {}
+
+void ParentalHandoffScreenHandler::Show(const base::string16& title,
+                                        const base::string16& subtitle) {
+  base::DictionaryValue data;
+  data.SetString(kTitle, title);
+  data.SetString(kSubTitle, subtitle);
+
+  ShowScreenWithData(kScreenId, &data);
+}
+
+void ParentalHandoffScreenHandler::Bind(ParentalHandoffScreen* screen) {
+  screen_ = screen;
+  BaseScreenHandler::SetBaseScreen(screen_);
+}
+
+void ParentalHandoffScreenHandler::Unbind() {
+  screen_ = nullptr;
+  BaseScreenHandler::SetBaseScreen(nullptr);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.h
new file mode 100644
index 0000000..91fbdee
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.h
@@ -0,0 +1,67 @@
+// 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 CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_PARENTAL_HANDOFF_SCREEN_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_PARENTAL_HANDOFF_SCREEN_HANDLER_H_
+
+#include "base/strings/string16.h"
+#include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
+
+namespace login {
+class LocalizedValuesBuilder;
+}  // namespace login
+
+namespace chromeos {
+
+class ParentalHandoffScreen;
+class JSCallsContainer;
+
+// Interface for dependency injection between ParentalHandoffScreen and its
+// WebUI representation.
+class ParentalHandoffScreenView {
+ public:
+  constexpr static StaticOobeScreenId kScreenId{"parental-handoff"};
+
+  virtual ~ParentalHandoffScreenView() = default;
+
+  // Shows the contents of the screen.
+  virtual void Show(const base::string16& title,
+                    const base::string16& subtitle) = 0;
+
+  // Binds |screen| to the view.
+  virtual void Bind(ParentalHandoffScreen* screen) = 0;
+
+  // Unbinds the screen from the view.
+  virtual void Unbind() = 0;
+};
+
+class ParentalHandoffScreenHandler : public BaseScreenHandler,
+                                     public ParentalHandoffScreenView {
+ public:
+  using TView = ParentalHandoffScreenView;
+
+  explicit ParentalHandoffScreenHandler(JSCallsContainer* js_calls_container);
+  ParentalHandoffScreenHandler(const ParentalHandoffScreenHandler&) = delete;
+  ParentalHandoffScreenHandler& operator=(const ParentalHandoffScreenHandler&) =
+      delete;
+  ~ParentalHandoffScreenHandler() override;
+
+ private:
+  // BaseScreenHandler:
+  void DeclareLocalizedValues(
+      ::login::LocalizedValuesBuilder* builder) override;
+  void Initialize() override;
+
+  // Shows the contents of the screen.
+  void Show(const base::string16& title,
+            const base::string16& subtitle) override;
+  void Bind(ParentalHandoffScreen* screen) override;
+  void Unbind() override;
+
+  ParentalHandoffScreen* screen_ = nullptr;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_PARENTAL_HANDOFF_SCREEN_HANDLER_H_
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index 51d37cd..3097287 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -989,23 +989,12 @@
   if (!web_app_provider_->registrar().IsInstalled(app_id))
     return;
 
+  InstallOsHooks(app_id);
+
   web_app_provider_->registry_controller().SetAppIsLocallyInstalled(app_id,
                                                                     true);
   web_app_provider_->registry_controller().SetAppInstallTime(app_id,
                                                              base::Time::Now());
-  web_app::InstallOsHooksOptions options;
-  options.add_to_desktop = true;
-  options.add_to_quick_launch_bar = false;
-  options.os_hooks[web_app::OsHookType::kShortcuts] = true;
-  options.os_hooks[web_app::OsHookType::kShortcutsMenu] = true;
-  options.os_hooks[web_app::OsHookType::kFileHandlers] = true;
-  options.os_hooks[web_app::OsHookType::kRunOnOsLogin] = false;
-
-  web_app_provider_->os_integration_manager().InstallOsHooks(
-      app_id,
-      base::BindOnce(&AppLauncherHandler::OnOsHooksInstalled,
-                     weak_ptr_factory_.GetWeakPtr(), app_id),
-      /*web_application_info=*/nullptr, std::move(options));
 
   // Use the appAdded to update the app icon's color to no longer be
   // greyscale.
@@ -1218,6 +1207,10 @@
                 "Apps.Launcher.InstallAppFromLinkResult", install_result);
             if (!app_launcher_handler)
               return;
+            if (install_result ==
+                web_app::InstallResultCode::kSuccessNewInstall) {
+              app_launcher_handler->InstallOsHooks(app_id);
+            }
             if (install_result !=
                 web_app::InstallResultCode::kSuccessNewInstall) {
               app_launcher_handler->attempting_web_app_install_page_ordinal_ =
@@ -1357,3 +1350,19 @@
   Profile* profile = Profile::FromWebUI(web_ui());
   return extensions::ui_util::ShouldDisplayInNewTabPage(extension, profile);
 }
+
+void AppLauncherHandler::InstallOsHooks(const web_app::AppId& app_id) {
+  web_app::InstallOsHooksOptions options;
+  options.add_to_desktop = true;
+  options.add_to_quick_launch_bar = false;
+  options.os_hooks[web_app::OsHookType::kShortcuts] = true;
+  options.os_hooks[web_app::OsHookType::kShortcutsMenu] = true;
+  options.os_hooks[web_app::OsHookType::kFileHandlers] = true;
+  options.os_hooks[web_app::OsHookType::kRunOnOsLogin] = false;
+
+  web_app_provider_->os_integration_manager().InstallOsHooks(
+      app_id,
+      base::BindOnce(&AppLauncherHandler::OnOsHooksInstalled,
+                     weak_ptr_factory_.GetWeakPtr(), app_id),
+      /*web_application_info=*/nullptr, std::move(options));
+}
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.h b/chrome/browser/ui/webui/ntp/app_launcher_handler.h
index 99248748..81ab55d 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.h
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.h
@@ -212,6 +212,9 @@
   // True if the extension should be displayed.
   bool ShouldShow(const extensions::Extension* extension) const;
 
+  // Handle installing OS hooks for Web App installs from chrome://apps page.
+  void InstallOsHooks(const web_app::AppId& app_id);
+
   // The apps are represented in the extensions model, which
   // outlives us since it's owned by our containing profile.
   extensions::ExtensionService* const extension_service_;
diff --git a/chrome/browser/ui/webui/read_later/read_later.mojom b/chrome/browser/ui/webui/read_later/read_later.mojom
index ef7780d6..2fdbd30 100644
--- a/chrome/browser/ui/webui/read_later/read_later.mojom
+++ b/chrome/browser/ui/webui/read_later/read_later.mojom
@@ -43,6 +43,9 @@
 
   // Removes a read later entry.
   RemoveEntry(url.mojom.Url url);
+
+  // Notify the backend that the UI is ready to be shown.
+  ShowUI();
 };
 
 // WebUI-side handler for requests from the browser.
diff --git a/chrome/browser/ui/webui/read_later/read_later_page_handler.cc b/chrome/browser/ui/webui/read_later/read_later_page_handler.cc
index 601500c..d196d5e 100644
--- a/chrome/browser/ui/webui/read_later/read_later_page_handler.cc
+++ b/chrome/browser/ui/webui/read_later/read_later_page_handler.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/read_later/reading_list_model_factory.h"
+#include "chrome/browser/ui/webui/read_later/read_later_ui.h"
 #include "components/reading_list/core/reading_list_entry.h"
 #include "components/reading_list/core/reading_list_model.h"
 #include "components/url_formatter/url_formatter.h"
@@ -40,10 +41,12 @@
 
 ReadLaterPageHandler::ReadLaterPageHandler(
     mojo::PendingReceiver<read_later::mojom::PageHandler> receiver,
-    mojo::PendingRemote<read_later::mojom::Page> page)
+    mojo::PendingRemote<read_later::mojom::Page> page,
+    ReadLaterUI* read_later_ui)
     : receiver_(this, std::move(receiver)),
       page_(std::move(page)),
       browser_(chrome::FindLastActive()),
+      read_later_ui_(read_later_ui),
       clock_(base::DefaultClock::GetInstance()) {
   DCHECK(browser_);
 
@@ -93,6 +96,12 @@
   page_->ItemsChanged();
 }
 
+void ReadLaterPageHandler::ShowUI() {
+  auto embedder = read_later_ui_->embedder();
+  if (embedder)
+    embedder->ShowUI();
+}
+
 read_later::mojom::ReadLaterEntryPtr ReadLaterPageHandler::GetEntryData(
     const ReadingListEntry* entry) {
   auto entry_data = read_later::mojom::ReadLaterEntry::New();
diff --git a/chrome/browser/ui/webui/read_later/read_later_page_handler.h b/chrome/browser/ui/webui/read_later/read_later_page_handler.h
index 26d32c1..ba82f954 100644
--- a/chrome/browser/ui/webui/read_later/read_later_page_handler.h
+++ b/chrome/browser/ui/webui/read_later/read_later_page_handler.h
@@ -12,7 +12,6 @@
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "ui/webui/mojo_web_ui_controller.h"
 
 namespace base {
 class Clock;
@@ -20,6 +19,7 @@
 
 class Browser;
 class GURL;
+class ReadLaterUI;
 class ReadingListEntry;
 class ReadingListModel;
 
@@ -27,7 +27,8 @@
  public:
   ReadLaterPageHandler(
       mojo::PendingReceiver<read_later::mojom::PageHandler> receiver,
-      mojo::PendingRemote<read_later::mojom::Page> page);
+      mojo::PendingRemote<read_later::mojom::Page> page,
+      ReadLaterUI* read_later_ui);
   ReadLaterPageHandler(const ReadLaterPageHandler&) = delete;
   ReadLaterPageHandler& operator=(const ReadLaterPageHandler&) = delete;
   ~ReadLaterPageHandler() override;
@@ -37,6 +38,7 @@
   void OpenSavedEntry(const GURL& url) override;
   void UpdateReadStatus(const GURL& url, bool read) override;
   void RemoveEntry(const GURL& url) override;
+  void ShowUI() override;
 
  private:
   // Gets the reading list entry data used for displaying to the user and
@@ -52,6 +54,9 @@
   mojo::Receiver<read_later::mojom::PageHandler> receiver_;
   mojo::Remote<read_later::mojom::Page> page_;
   Browser* const browser_;
+  // ReadLaterPageHandler is owned by |read_later_ui_| and so we expect
+  // |read_later_ui_| to remain valid for the lifetime of |this|.
+  ReadLaterUI* const read_later_ui_;
 
   base::Clock* clock_;
 
diff --git a/chrome/browser/ui/webui/read_later/read_later_page_handler_unittest.cc b/chrome/browser/ui/webui/read_later/read_later_page_handler_unittest.cc
index c209a43..c7a180b 100644
--- a/chrome/browser/ui/webui/read_later/read_later_page_handler_unittest.cc
+++ b/chrome/browser/ui/webui/read_later/read_later_page_handler_unittest.cc
@@ -59,7 +59,8 @@
       mojo::PendingRemote<read_later::mojom::Page> page)
       : ReadLaterPageHandler(
             mojo::PendingReceiver<read_later::mojom::PageHandler>(),
-            std::move(page)) {}
+            std::move(page),
+            nullptr) {}
 };
 
 class TestReadLaterPageHandlerTest : public BrowserWithTestWindowTest {
diff --git a/chrome/browser/ui/webui/read_later/read_later_ui.cc b/chrome/browser/ui/webui/read_later/read_later_ui.cc
index 5535ada..5b31ce8 100644
--- a/chrome/browser/ui/webui/read_later/read_later_ui.cc
+++ b/chrome/browser/ui/webui/read_later/read_later_ui.cc
@@ -34,7 +34,7 @@
 }  // namespace
 
 ReadLaterUI::ReadLaterUI(content::WebUI* web_ui)
-    : ui::MojoWebUIController(web_ui) {
+    : ui::MojoBubbleWebUIController(web_ui) {
   content::WebUIDataSource* source =
       content::WebUIDataSource::Create(chrome::kChromeUIReadLaterHost);
   source->AddResourcePath("read_later.mojom-lite.js",
@@ -72,5 +72,5 @@
     mojo::PendingReceiver<read_later::mojom::PageHandler> receiver) {
   DCHECK(page);
   page_handler_ = std::make_unique<ReadLaterPageHandler>(std::move(receiver),
-                                                         std::move(page));
+                                                         std::move(page), this);
 }
diff --git a/chrome/browser/ui/webui/read_later/read_later_ui.h b/chrome/browser/ui/webui/read_later/read_later_ui.h
index a558b72..5532f286 100644
--- a/chrome/browser/ui/webui/read_later/read_later_ui.h
+++ b/chrome/browser/ui/webui/read_later/read_later_ui.h
@@ -12,11 +12,11 @@
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
-#include "ui/webui/mojo_web_ui_controller.h"
+#include "ui/webui/mojo_bubble_web_ui_controller.h"
 
 class ReadLaterPageHandler;
 
-class ReadLaterUI : public ui::MojoWebUIController,
+class ReadLaterUI : public ui::MojoBubbleWebUIController,
                     public read_later::mojom::PageHandlerFactory {
  public:
   explicit ReadLaterUI(content::WebUI* web_ui);
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 3bab15e..2f96eb7 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1603216608-9fdc3766d62145cb23e4981f379b4b4bd1eab8ae.profdata
+chrome-linux-master-1603238376-41278602b445da41d1916a61de8117b0857ab174.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 3b56323..2cb8fd1 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1603216608-7529e831dfcfdc3eeb93d3e8d9f23aaded5766b2.profdata
+chrome-mac-master-1603238376-a0754723f0cd6eaa7fc2494ab4a5f08c0cee1720.profdata
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 1816073c..3607f95 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -118,7 +118,7 @@
     "https://support.google.com/chrome?p=cpn_cookies";
 
 const char kCpuX86Sse2ObsoleteURL[] =
-    "https://support.google.com/chrome/?p=unsupported_cpu";
+    "https://support.google.com/chrome/?p=chrome_update_sse3";
 
 const char kCrashReasonURL[] =
 #if defined(OS_CHROMEOS)
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 2f6f4f4..245c97f7 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -224,6 +224,8 @@
 const char kChromeUIArcGraphicsTracingURL[] = "chrome://arc-graphics-tracing/";
 const char kChromeUIArcOverviewTracingHost[] = "arc-overview-tracing";
 const char kChromeUIArcOverviewTracingURL[] = "chrome://arc-overview-tracing/";
+const char kChromeUIArcPowerControlHost[] = "arc-power-control";
+const char kChromeUIArcPowerControlURL[] = "chrome://arc-power-control/";
 const char kChromeUIAssistantOptInHost[] = "assistant-optin";
 const char kChromeUIAssistantOptInURL[] = "chrome://assistant-optin/";
 const char kChromeUIAppDisabledHost[] = "app-disabled";
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index c57f9936..c8a3195 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -219,6 +219,8 @@
 extern const char kChromeUIArcGraphicsTracingURL[];
 extern const char kChromeUIArcOverviewTracingHost[];
 extern const char kChromeUIArcOverviewTracingURL[];
+extern const char kChromeUIArcPowerControlHost[];
+extern const char kChromeUIArcPowerControlURL[];
 extern const char kChromeUIAssistantOptInHost[];
 extern const char kChromeUIAssistantOptInURL[];
 extern const char kChromeUIAppDisabledHost[];
diff --git a/chrome/credential_provider/gaiacp/scoped_user_profile.cc b/chrome/credential_provider/gaiacp/scoped_user_profile.cc
index 3f8a4e7..e9ba0ba 100644
--- a/chrome/credential_provider/gaiacp/scoped_user_profile.cc
+++ b/chrome/credential_provider/gaiacp/scoped_user_profile.cc
@@ -327,8 +327,15 @@
       continue;
     }
 
-    std::string current_picture_url =
-        base::UTF16ToUTF8(picture_url) + base::StringPrintf("=s%i", image_size);
+    std::size_t found = base::UTF16ToUTF8(picture_url).rfind("=s");
+    std::string current_picture_url;
+    if (found != std::string::npos)
+      current_picture_url = base::UTF16ToUTF8(picture_url).substr(0, found) +
+                            base::StringPrintf("=s%i", image_size);
+    else
+      // Fallback to default picture url if parsing fails.
+      current_picture_url = base::UTF16ToUTF8(picture_url) +
+                            base::StringPrintf("=s%i", image_size);
 
     auto fetcher = WinHttpUrlFetcher::Create(GURL(current_picture_url));
     if (!fetcher) {
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 631c0e48..cde60cbe 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2508,6 +2508,7 @@
         "../browser/chromeos/login/screens/multidevice_setup_screen_browsertest.cc",
         "../browser/chromeos/login/screens/network_screen_browsertest.cc",
         "../browser/chromeos/login/screens/packaged_license_screen_browsertest.cc",
+        "../browser/chromeos/login/screens/parental_handoff_screen_browsertest.cc",
         "../browser/chromeos/login/screens/recommend_apps/scoped_test_recommend_apps_fetcher_factory.cc",
         "../browser/chromeos/login/screens/recommend_apps/scoped_test_recommend_apps_fetcher_factory.h",
         "../browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc",
@@ -5539,7 +5540,6 @@
     sources += [
       "../browser/safe_browsing/advanced_protection_status_manager_factory_unittest.cc",
       "../browser/safe_browsing/advanced_protection_status_manager_unittest.cc",
-      "../browser/safe_browsing/browser_feature_extractor_unittest.cc",
       "../browser/safe_browsing/chrome_enterprise_url_lookup_service_unittest.cc",
       "../browser/safe_browsing/client_side_detection_host_unittest.cc",
       "../browser/safe_browsing/client_side_detection_service_factory_unittest.cc",
diff --git a/chrome/test/base/test_browser_window.cc b/chrome/test/base/test_browser_window.cc
index b499095..1f24988 100644
--- a/chrome/test/base/test_browser_window.cc
+++ b/chrome/test/base/test_browser_window.cc
@@ -14,11 +14,12 @@
 // Helpers --------------------------------------------------------------------
 
 std::unique_ptr<Browser> CreateBrowserWithTestWindowForParams(
-    Browser::CreateParams* params) {
+    Browser::CreateParams params) {
+  DCHECK(!params.window);
   TestBrowserWindow* window = new TestBrowserWindow;
   new TestBrowserWindowOwner(window);
-  params->window = window;
-  return std::make_unique<Browser>(*params);
+  params.window = window;
+  return std::make_unique<Browser>(params);
 }
 
 // TestBrowserWindow::TestLocationBar -----------------------------------------
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index fd8fb57..6127060b 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -259,6 +259,6 @@
 
 // Helper that handle the lifetime of TestBrowserWindow instances.
 std::unique_ptr<Browser> CreateBrowserWithTestWindowForParams(
-    Browser::CreateParams* params);
+    Browser::CreateParams params);
 
 #endif  // CHROME_TEST_BASE_TEST_BROWSER_WINDOW_H_
diff --git a/chrome/test/data/webui/chromeos/diagnostics/diagnostics_test_utils.js b/chrome/test/data/webui/chromeos/diagnostics/diagnostics_test_utils.js
index 2cd8e1c..45d8f4d 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/diagnostics_test_utils.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/diagnostics_test_utils.js
@@ -31,3 +31,13 @@
 export function getRealtimeCpuChartElement(element) {
   return element.shadowRoot.querySelector('realtime-cpu-chart');
 }
+
+/**
+ * Helper function for getting an array of routine-result-entry
+ * element from a routine-result-list.
+ * @param {!HTMLElement} element
+ * @return {!Array<!HTMLElement>}
+ */
+export function getResultEntries(element) {
+  return element.shadowRoot.querySelectorAll('routine-result-entry');
+}
diff --git a/chrome/test/data/webui/chromeos/diagnostics/routine_result_list_test.js b/chrome/test/data/webui/chromeos/diagnostics/routine_result_list_test.js
index 30335f3d..2bac3bc1 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/routine_result_list_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/routine_result_list_test.js
@@ -5,8 +5,13 @@
 // TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
 import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 import 'chrome://diagnostics/routine_result_list.js';
+
+import {RoutineName} from 'chrome://diagnostics/diagnostics_types.js';
+import {ExecutionProgress, ResultStatusItem} from 'chrome://diagnostics/routine_list_executor.js';
 import {flushTasks} from 'chrome://test/test_util.m.js';
 
+import * as diagnostics_test_utils from './diagnostics_test_utils.js';
+
 suite('RoutineResultListTest', () => {
   /** @type {?HTMLElement} */
   let routineResultListElement = null;
@@ -22,7 +27,12 @@
     routineResultListElement = null;
   });
 
-  function initializeRoutineResultList() {
+  /**
+   * Initializes the routine-result-list and sets the list of routines.
+   * @param {!Array<!RoutineName>} routines
+   * @return {!Promise}
+   */
+  function initializeRoutineResultList(routines) {
     assertFalse(!!routineResultListElement);
 
     // Add the entry to the DOM.
@@ -30,14 +40,76 @@
     assertTrue(!!routineResultListElement);
     document.body.appendChild(routineResultListElement);
 
+    // Initialize the routines.
+    routineResultListElement.initializeTestRun(routines);
+
     return flushTasks();
   }
 
+  /**
+   * Clear the routine-result-list.
+   * @return {!Promise}
+   */
+  function clearRoutineResultList() {
+    routineResultListElement.clearRoutines();
+    return flushTasks();
+  }
+
+  /**
+   * Returns an array of the entries in the list.
+   * @return {!Array<!RoutineResultEntry>}
+   */
+  function getEntries() {
+    return diagnostics_test_utils.getResultEntries(routineResultListElement);
+  }
+
   test('ElementRendered', () => {
-    return initializeRoutineResultList().then(() => {
+    return initializeRoutineResultList([]).then(() => {
       // Verify the element rendered.
       let div = routineResultListElement.$$('#resultListContainer');
       assertTrue(!!div);
     });
   });
+
+  test('EmptyByDefault', () => {
+    return initializeRoutineResultList([]).then(() => {
+      assertEquals(0, getEntries().length);
+    });
+  });
+
+  test('InitializedRoutines', () => {
+    /** @type {!Array<!RoutineName>} */
+    const routines = [
+      RoutineName.kCpuCache,
+      RoutineName.kFloatingPoint,
+    ];
+
+    return initializeRoutineResultList(routines).then(() => {
+      assertEquals(routines.length, getEntries().length);
+      getEntries().forEach((entry, index) => {
+        // Routines are initialized in the unstarted state.
+        let status = new ResultStatusItem(routines[index]);
+        status.progress = ExecutionProgress.kNotStarted;
+        assertDeepEquals(status, entry.item);
+      });
+    });
+  });
+
+  test('InitializeThenClearRoutines', () => {
+    /** @type {!Array<!RoutineName>} */
+    const routines = [
+      RoutineName.kCpuCache,
+      RoutineName.kFloatingPoint,
+    ];
+
+    return initializeRoutineResultList(routines)
+        .then(() => {
+          assertEquals(routines.length, getEntries().length);
+          return clearRoutineResultList();
+        })
+        .then(() => {
+          // List is empty after clearing.
+          assertEquals(0, getEntries().length);
+        });
+  });
 });
diff --git a/chrome/test/data/webui/read_later/test_read_later_api_proxy.js b/chrome/test/data/webui/read_later/test_read_later_api_proxy.js
index 2475010c..6f4c055 100644
--- a/chrome/test/data/webui/read_later/test_read_later_api_proxy.js
+++ b/chrome/test/data/webui/read_later/test_read_later_api_proxy.js
@@ -15,6 +15,7 @@
       'openSavedEntry',
       'updateReadStatus',
       'removeEntry',
+      'showUI',
     ]);
 
     /** @type {!readLater.mojom.PageCallbackRouter} */
@@ -46,6 +47,11 @@
   }
 
   /** @override */
+  showUI() {
+    this.methodCalled('showUI');
+  }
+
+  /** @override */
   getCallbackRouter() {
     return this.callbackRouter;
   }
diff --git a/chrome/updater/app/server/mac/service_delegate.mm b/chrome/updater/app/server/mac/service_delegate.mm
index ff625caa..89c73c32 100644
--- a/chrome/updater/app/server/mac/service_delegate.mm
+++ b/chrome/updater/app/server/mac/service_delegate.mm
@@ -61,6 +61,25 @@
 }
 
 #pragma mark CRUUpdateChecking
+- (void)getVersionWithReply:(void (^_Nonnull)(NSString* version))reply {
+  auto cb =
+      base::BindOnce(base::RetainBlock(^(const base::Version& updaterVersion) {
+        VLOG(0) << "GetVersion complete: version = "
+                << (updaterVersion.IsValid() ? updaterVersion.GetString() : "");
+        if (reply) {
+          reply(base::SysUTF8ToNSString(
+              updaterVersion.IsValid() ? updaterVersion.GetString() : nil));
+        }
+
+        _appServer->TaskCompleted();
+      }));
+
+  _appServer->TaskStarted();
+  _callbackRunner->PostTask(
+      FROM_HERE, base::BindOnce(&updater::UpdateService::GetVersion, _service,
+                                std::move(cb)));
+}
+
 - (void)checkForUpdatesWithUpdateState:(id<CRUUpdateStateObserving>)updateState
                                  reply:(void (^_Nonnull)(int rc))reply {
   auto cb =
diff --git a/chrome/updater/app/server/mac/service_protocol.h b/chrome/updater/app/server/mac/service_protocol.h
index 65926f03..d3af4d4 100644
--- a/chrome/updater/app/server/mac/service_protocol.h
+++ b/chrome/updater/app/server/mac/service_protocol.h
@@ -25,6 +25,10 @@
 // Protocol for the XPC update checking service.
 @protocol CRUUpdateChecking <NSObject>
 
+// Checks for the updater's version and returns the result in the reply block.
+- (void)getVersionWithReply:
+    (void (^_Nonnull)(NSString* _Nullable version))reply;
+
 // Checks for updates and returns the result in the reply block.
 - (void)checkForUpdatesWithUpdateState:
             (CRUUpdateStateObserver* _Nonnull)updateState
diff --git a/chrome/updater/mac/update_service_out_of_process.mm b/chrome/updater/mac/update_service_out_of_process.mm
index 7a8f275d..e2a55a91 100644
--- a/chrome/updater/mac/update_service_out_of_process.mm
+++ b/chrome/updater/mac/update_service_out_of_process.mm
@@ -7,6 +7,7 @@
 #import <Foundation/Foundation.h>
 
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -14,9 +15,9 @@
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/scoped_nsobject.h"
-#include "base/notreached.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/threading/sequenced_task_runner_handle.h"
+#include "base/version.h"
 #import "chrome/updater/app/server/mac/service_protocol.h"
 #import "chrome/updater/app/server/mac/update_service_wrappers.h"
 #import "chrome/updater/mac/xpc_service_names.h"
@@ -74,6 +75,17 @@
   [super dealloc];
 }
 
+- (void)getVersionWithReply:(void (^_Nonnull)(NSString* version))reply {
+  auto errorHandler = ^(NSError* xpcError) {
+    LOG(ERROR) << "XPC connection failed: "
+               << base::SysNSStringToUTF8([xpcError description]);
+    reply(nil);
+  };
+
+  [[_updateCheckXPCConnection remoteObjectProxyWithErrorHandler:errorHandler]
+      getVersionWithReply:reply];
+}
+
 - (void)registerForUpdatesWithAppId:(NSString* _Nullable)appId
                           brandCode:(NSString* _Nullable)brandCode
                                 tag:(NSString* _Nullable)tag
@@ -144,6 +156,21 @@
   callback_runner_ = base::SequencedTaskRunnerHandle::Get();
 }
 
+void UpdateServiceOutOfProcess::GetVersion(
+    base::OnceCallback<void(const base::Version&)> callback) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  __block base::OnceCallback<void(const base::Version&)> block_callback =
+      std::move(callback);
+  auto reply = ^(NSString* version) {
+    callback_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(std::move(block_callback),
+                       base::Version(base::SysNSStringToUTF8(version))));
+  };
+  [client_ getVersionWithReply:reply];
+}
+
 void UpdateServiceOutOfProcess::RegisterApp(
     const RegistrationRequest& request,
     base::OnceCallback<void(const RegistrationResponse&)> callback) {
@@ -188,14 +215,6 @@
   [client_ checkForUpdatesWithUpdateState:stateObserver.get() reply:reply];
 }
 
-void UpdateServiceOutOfProcess::GetVersion(
-    base::OnceCallback<void(const base::Version&)> callback) const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  // TODO(crbug.com/1140270) - implement for macOS.
-  NOTREACHED();
-}
-
 void UpdateServiceOutOfProcess::Update(const std::string& app_id,
                                        UpdateService::Priority priority,
                                        StateChangeCallback state_update,
diff --git a/chrome/updater/test/test_app/update_client_mac.mm b/chrome/updater/test/test_app/update_client_mac.mm
index f9617d3..86f6e7f 100644
--- a/chrome/updater/test/test_app/update_client_mac.mm
+++ b/chrome/updater/test/test_app/update_client_mac.mm
@@ -58,6 +58,17 @@
   return self;
 }
 
+- (void)getVersionWithReply:(void (^_Nonnull)(NSString* version))reply {
+  auto errorHandler = ^(NSError* xpcError) {
+    LOG(ERROR) << "XPC Connection failed: "
+               << base::SysNSStringToUTF8([xpcError description]);
+    reply(nil);
+  };
+
+  [[_xpcConnection remoteObjectProxyWithErrorHandler:errorHandler]
+      getVersionWithReply:reply];
+}
+
 - (void)registerForUpdatesWithAppId:(NSString* _Nullable)appId
                           brandCode:(NSString* _Nullable)brandCode
                                 tag:(NSString* _Nullable)tag
diff --git a/chrome/updater/win/setup/setup_util.cc b/chrome/updater/win/setup/setup_util.cc
index bd479e7..54ecd25a 100644
--- a/chrome/updater/win/setup/setup_util.cc
+++ b/chrome/updater/win/setup/setup_util.cc
@@ -76,7 +76,7 @@
 }
 
 std::vector<base::FilePath> ParseFilesFromDeps(const base::FilePath& deps) {
-  constexpr size_t kDepsFileSizeMax = 0x2000;  // 8KB.
+  constexpr size_t kDepsFileSizeMax = 0x4000;  // 16KB.
   std::string contents;
   if (!base::ReadFileToStringWithMaxSize(deps, &contents, kDepsFileSizeMax))
     return {};
diff --git a/chromeos/components/diagnostics_ui/resources/routine_result_list.html b/chromeos/components/diagnostics_ui/resources/routine_result_list.html
index 56524c98c..b804119 100644
--- a/chromeos/components/diagnostics_ui/resources/routine_result_list.html
+++ b/chromeos/components/diagnostics_ui/resources/routine_result_list.html
@@ -2,4 +2,9 @@
 </style>
 
 <div id="resultListContainer">
+  <dom-repeat id="resultList" items="[[results_]]">
+    <template>
+      <routine-result-entry item="[[item]]"></routine-result-entry>
+    </template>
+  </dom-repeat>
 </div>
diff --git a/chromeos/components/diagnostics_ui/resources/routine_result_list.js b/chromeos/components/diagnostics_ui/resources/routine_result_list.js
index 0a136cf..3c54a9e 100644
--- a/chromeos/components/diagnostics_ui/resources/routine_result_list.js
+++ b/chromeos/components/diagnostics_ui/resources/routine_result_list.js
@@ -4,8 +4,11 @@
 
 import './diagnostics_card.js';
 import './diagnostics_shared_css.js';
+import './routine_result_entry.js';
 
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {RoutineName} from './diagnostics_types.js';
+import {ResultStatusItem} from './routine_list_executor.js'
 
 /**
  * @fileoverview
@@ -16,7 +19,42 @@
 
   _template: html`{__html_template__}`,
 
-  properties: {},
+  properties: {
+    /** @private {!Array<!ResultStatusItem>} */
+    results_: {
+      type: Array,
+      value: () => [],
+    },
+  },
+
+  /**
+   * Resets the list and creates a new list with all routines in the unstarted
+   * state. Called by the parent RoutineResultSection when the user starts
+   * a test run.
+   * @param {!Array<!RoutineName>} routines
+   */
+  initializeTestRun(routines) {
+    this.clearRoutines();
+    routines.forEach((routine) => {
+      this.addRoutine_(routine);
+    });
+  },
+
+  /**
+   * Removes all the routines from the list.
+   */
+  clearRoutines() {
+    this.splice('results_', 0, this.results_.length);
+  },
+
+  /**
+   * Add a new unstarted routine to the end of the list.
+   * @param {!RoutineName} routine
+   * @private
+   */
+  addRoutine_(routine) {
+    this.push('results_', new ResultStatusItem(routine));
+  },
 
   /** @override */
   created() {},
diff --git a/chromeos/services/ime/BUILD.gn b/chromeos/services/ime/BUILD.gn
index ce82a83..3640a51 100644
--- a/chromeos/services/ime/BUILD.gn
+++ b/chromeos/services/ime/BUILD.gn
@@ -17,12 +17,29 @@
   ]
 }
 
+source_set("decoder") {
+  sources = [
+    "ime_decoder.cc",
+    "ime_decoder.h",
+  ]
+
+  deps = [
+    ":constants",
+    "//base",
+    "//chromeos/constants",
+    "//chromeos/services/ime/public/cpp:buildflags",
+    "//chromeos/services/ime/public/cpp/shared_lib:interfaces",
+  ]
+}
+
 source_set("lib") {
   sources = [
     "decoder/decoder_engine.cc",
     "decoder/decoder_engine.h",
     "decoder/downloader_impl.cc",
     "decoder/downloader_impl.h",
+    "decoder/proto_conversion.cc",
+    "decoder/proto_conversion.h",
     "ime_service.cc",
     "ime_service.h",
     "input_engine.cc",
@@ -31,6 +48,7 @@
 
   deps = [
     ":constants",
+    ":decoder",
     "//base",
     "//chromeos/constants",
     "//chromeos/services/ime/public/cpp:buildflags",
@@ -49,6 +67,7 @@
 
   deps = [
     ":constants",
+    ":decoder",
     "//base",
     "//chromeos/services/ime/public/cpp:buildflags",
     "//sandbox/linux:sandbox_services",
@@ -68,10 +87,15 @@
     "//base",
     "//base/test:test_support",
     "//chromeos/services/ime/public/mojom",
+    "//chromeos/services/ime/public/proto:messages_proto",
     "//mojo/public/cpp/bindings",
     "//services/network:test_support",
     "//testing/gmock",
     "//testing/gtest",
   ]
-  sources = [ "ime_service_unittest.cc" ]
+  sources = [
+    "decoder/decoder_engine_unittest.cc",
+    "decoder/proto_conversion_unittest.cc",
+    "ime_service_unittest.cc",
+  ]
 }
diff --git a/chromeos/services/ime/constants.cc b/chromeos/services/ime/constants.cc
index 1222d3f..e8c3a58 100644
--- a/chromeos/services/ime/constants.cc
+++ b/chromeos/services/ime/constants.cc
@@ -27,18 +27,6 @@
     FILE_PATH_LITERAL("/home/chronos/" IME_DIR_STRING);
 const base::FilePath::CharType kLanguageDataDirName[] =
     FILE_PATH_LITERAL("google");
-const char kCrosImeDecoderLib[] = "libimedecoder.so";
-
-bool ImeDecoderInstalled() {
-  base::FilePath lib_path("/usr");
-#if defined(__x86_64__) || defined(__aarch64__)
-  lib_path = lib_path.Append("lib64");
-#else
-  lib_path = lib_path.Append("lib");
-#endif
-  lib_path = lib_path.Append(kCrosImeDecoderLib);
-  return base::PathExists(lib_path);
-}
 #else
 // IME service does not support third-party IME yet, so the paths below kind
 // of act like a placeholder. In the future, put some well-designed paths here.
@@ -50,12 +38,6 @@
     FILE_PATH_LITERAL("/tmp/" IME_DIR_STRING);
 const base::FilePath::CharType kLanguageDataDirName[] =
     FILE_PATH_LITERAL("data");
-// IME service does not support third-party IME decoder yet.
-const char kCrosImeDecoderLib[] = "";
-
-bool ImeDecoderInstalled() {
-  return false;
-}
 #endif
 
 const char kGoogleKeyboardDownloadDomain[] = "dl.google.com";
diff --git a/chromeos/services/ime/constants.h b/chromeos/services/ime/constants.h
index c3da3a6..2d70d88b5 100644
--- a/chromeos/services/ime/constants.h
+++ b/chromeos/services/ime/constants.h
@@ -44,13 +44,6 @@
 // The domain of Google Keyboard language dictionary download URL.
 COMPONENT_EXPORT(CHROMEOS_IME_CONSTANTS)
 extern const char kGoogleKeyboardDownloadDomain[];
-
-// The name of ChromeOS IME decoder shared Library.
-COMPONENT_EXPORT(CHROMEOS_IME_CONSTANTS)
-extern const char kCrosImeDecoderLib[];
-
-// Whether IME decoder is installed.
-COMPONENT_EXPORT(CHROMEOS_IME_CONSTANTS) bool ImeDecoderInstalled();
 }  // namespace ime
 }  // namespace chromeos
 
diff --git a/chromeos/services/ime/decoder/decoder_engine.cc b/chromeos/services/ime/decoder/decoder_engine.cc
index 4980ecc..3477d074 100644
--- a/chromeos/services/ime/decoder/decoder_engine.cc
+++ b/chromeos/services/ime/decoder/decoder_engine.cc
@@ -8,6 +8,8 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "chromeos/services/ime/constants.h"
+#include "chromeos/services/ime/decoder/proto_conversion.h"
+#include "chromeos/services/ime/ime_decoder.h"
 #include "chromeos/services/ime/public/cpp/buildflags.h"
 #include "chromeos/services/ime/public/proto/messages.pb.h"
 
@@ -16,15 +18,23 @@
 
 namespace {
 
-// Whether to create a fake main entry.
-bool g_fake_main_entry_for_testing = false;
+ImeEngineMainEntry* g_fake_main_entry_for_testing = nullptr;
 
-// A client delegate that makes calls on client side.
+using ReplyCallback =
+    base::RepeatingCallback<void(const std::vector<uint8_t>&)>;
+
+// A client delegate passed to the shared library in order for the
+// shared library to send replies back to the engine.
 class ClientDelegate : public ImeClientDelegate {
  public:
+  // All replies from the shared library will be sent to both |remote| and
+  // |callback|.
   ClientDelegate(const std::string& ime_spec,
-                 mojo::PendingRemote<mojom::InputChannel> remote)
-      : ime_spec_(ime_spec), client_remote_(std::move(remote)) {
+                 mojo::PendingRemote<mojom::InputChannel> remote,
+                 ReplyCallback callback)
+      : ime_spec_(ime_spec),
+        client_remote_(std::move(remote)),
+        callback_(callback) {
     client_remote_.set_disconnect_handler(base::BindOnce(
         &ClientDelegate::OnDisconnected, base::Unretained(this)));
   }
@@ -37,6 +47,7 @@
     if (client_remote_ && client_remote_.is_bound()) {
       std::vector<uint8_t> msg(data, data + size);
       client_remote_->ProcessMessage(msg, base::DoNothing());
+      callback_.Run(msg);
     }
   }
 
@@ -53,25 +64,27 @@
 
   // The InputChannel remote used to talk to the client.
   mojo::Remote<mojom::InputChannel> client_remote_;
+
+  ReplyCallback callback_;
 };
 
-std::vector<uint8_t> SerializeMessage(ime::PublicMessage message) {
-  ime::Wrapper wrapper;
+std::vector<uint8_t> WrapAndSerializeMessage(PublicMessage message) {
+  Wrapper wrapper;
   *wrapper.mutable_public_message() = std::move(message);
-  std::vector<uint8_t> output;
-  wrapper.SerializeToArray(output.data(), wrapper.ByteSizeLong());
+  std::vector<uint8_t> output(wrapper.ByteSizeLong());
+  wrapper.SerializeToArray(output.data(), output.size());
   return output;
 }
 
 }  // namespace
 
-void FakeEngineMainEntryForTesting() {
-  g_fake_main_entry_for_testing = true;
+void FakeEngineMainEntryForTesting(ImeEngineMainEntry* main_entry) {
+  g_fake_main_entry_for_testing = main_entry;
 }
 
 DecoderEngine::DecoderEngine(ImeCrosPlatform* platform) : platform_(platform) {
   if (g_fake_main_entry_for_testing) {
-    // TODO(b/156897880): Add a fake main entry.
+    engine_main_entry_ = g_fake_main_entry_for_testing;
   } else {
     if (!TryLoadDecoder()) {
       LOG(WARNING) << "DecoderEngine INIT INCOMPLETED.";
@@ -82,33 +95,15 @@
 DecoderEngine::~DecoderEngine() {}
 
 bool DecoderEngine::TryLoadDecoder() {
-  if (!ImeDecoderInstalled()) {
-    LOG(WARNING) << "IME decoder shared library is not installed.";
-    return false;
-  }
-
   if (engine_main_entry_)
     return true;
 
-  // Load the decoder whose DSO has been preloaded before sandbox is engaged.
-  base::FilePath lib_path(kCrosImeDecoderLib);
-  library_ = base::ScopedNativeLibrary(lib_path);
-
-  if (!library_.is_valid()) {
-    LOG(ERROR) << "Failed to load decoder shared library from: " << lib_path
-               << ", error: " << library_.GetError()->ToString();
-    return false;
+  auto* decoder = ImeDecoder::GetInstance();
+  if (decoder->GetStatus() == ImeDecoder::Status::kSuccess) {
+    engine_main_entry_ = decoder->CreateMainEntry(platform_);
+    return true;
   }
-
-  // Prepare the decoder data directory before initialization.
-  base::FilePath data_dir(platform_->GetImeUserHomeDir());
-  base::CreateDirectory(data_dir.Append(kLanguageDataDirName));
-
-  ImeMainEntryCreateFn createMainEntryFn =
-      reinterpret_cast<ImeMainEntryCreateFn>(
-          library_.GetFunctionPointer(IME_MAIN_ENTRY_CREATE_FN_NAME));
-  engine_main_entry_ = createMainEntryFn(platform_);
-  return true;
+  return false;
 }
 
 bool DecoderEngine::BindRequest(
@@ -122,7 +117,9 @@
     // make safe calls on the client.
     if (engine_main_entry_->ActivateIme(
             ime_spec.c_str(),
-            new ClientDelegate(ime_spec, std::move(remote)))) {
+            new ClientDelegate(ime_spec, std::move(remote),
+                               base::BindRepeating(&DecoderEngine::OnReply,
+                                                   base::Unretained(this))))) {
       decoder_channel_receivers_.Add(this, std::move(receiver));
       // TODO(https://crbug.com/837156): Registry connection error handler.
       return true;
@@ -141,11 +138,22 @@
 }
 
 void DecoderEngine::OnFocus() {
-  ime::PublicMessage message;
-  message.set_seq_id(current_seq_id_++);
-  *message.mutable_on_focus() = ime::OnFocus();
+  const uint64_t seq_id = current_seq_id_;
+  ++current_seq_id_;
 
-  ProcessMessage(SerializeMessage(std::move(message)), base::DoNothing());
+  ProcessMessage(WrapAndSerializeMessage(OnFocusToProto(seq_id)),
+                 base::DoNothing());
+}
+
+void DecoderEngine::OnKeyEvent(mojom::PhysicalKeyEventPtr event,
+                               OnKeyEventCallback callback) {
+  const uint64_t seq_id = current_seq_id_;
+  ++current_seq_id_;
+
+  pending_key_event_callbacks_.emplace(seq_id, std::move(callback));
+  ProcessMessage(
+      WrapAndSerializeMessage(OnKeyEventToProto(seq_id, std::move(event))),
+      base::DoNothing());
 }
 
 void DecoderEngine::ProcessMessage(const std::vector<uint8_t>& message,
@@ -160,5 +168,28 @@
   std::move(callback).Run(result);
 }
 
+void DecoderEngine::OnReply(const std::vector<uint8_t>& message) {
+  ime::Wrapper wrapper;
+  if (!wrapper.ParseFromArray(message.data(), message.size()) ||
+      !wrapper.has_public_message()) {
+    return;
+  }
+
+  const ime::PublicMessage& reply = wrapper.public_message();
+  switch (reply.param_case()) {
+    case ime::PublicMessage::kOnKeyEventReply: {
+      const auto it = pending_key_event_callbacks_.find(reply.seq_id());
+      CHECK(it != pending_key_event_callbacks_.end());
+      auto callback = std::move(it->second);
+      std::move(callback).Run(reply.on_key_event_reply().consumed());
+      pending_key_event_callbacks_.erase(it);
+      break;
+    }
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
 }  // namespace ime
 }  // namespace chromeos
diff --git a/chromeos/services/ime/decoder/decoder_engine.h b/chromeos/services/ime/decoder/decoder_engine.h
index 6b7f09e4..8609b534 100644
--- a/chromeos/services/ime/decoder/decoder_engine.h
+++ b/chromeos/services/ime/decoder/decoder_engine.h
@@ -13,8 +13,8 @@
 namespace chromeos {
 namespace ime {
 
-// Only used in tests to create a fake `ImeEngineMainEntry`.
-void FakeEngineMainEntryForTesting();
+// Only used in tests to set a fake `ImeEngineMainEntry`.
+void FakeEngineMainEntryForTesting(ImeEngineMainEntry* main_entry);
 
 // An enhanced implementation of the basic InputEngine which allows the input
 // engine to call a customized transliteration library (aka decoder) to provide
@@ -33,6 +33,8 @@
   void ProcessMessage(const std::vector<uint8_t>& message,
                       ProcessMessageCallback callback) override;
   void OnFocus() override;
+  void OnKeyEvent(mojom::PhysicalKeyEventPtr event,
+                  OnKeyEventCallback callback) override;
 
  private:
   // Try to load the decoding functions from some decoder shared library.
@@ -42,6 +44,10 @@
   // Returns whether the decoder shared library supports this ime_spec.
   bool IsImeSupportedByDecoder(const std::string& ime_spec);
 
+  // Called when there's a reply from the shared library.
+  // Deserializes |message| and converts it into Mojo calls to the receiver.
+  void OnReply(const std::vector<uint8_t>& message);
+
   // Shared library handle of the implementation for input logic with decoders.
   base::ScopedNativeLibrary library_;
 
@@ -52,7 +58,9 @@
   mojo::ReceiverSet<mojom::InputChannel> decoder_channel_receivers_;
 
   // Sequence ID for protobuf messages sent from the engine.
-  int current_seq_id_ = 0;
+  uint64_t current_seq_id_ = 0;
+
+  std::map<uint64_t, OnKeyEventCallback> pending_key_event_callbacks_;
 
   DISALLOW_COPY_AND_ASSIGN(DecoderEngine);
 };
diff --git a/chromeos/services/ime/decoder/decoder_engine_unittest.cc b/chromeos/services/ime/decoder/decoder_engine_unittest.cc
new file mode 100644
index 0000000..9eeac21
--- /dev/null
+++ b/chromeos/services/ime/decoder/decoder_engine_unittest.cc
@@ -0,0 +1,145 @@
+// 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 "chromeos/services/ime/decoder/decoder_engine.h"
+
+#include "base/test/bind_test_util.h"
+#include "base/test/task_environment.h"
+#include "chromeos/services/ime/decoder/proto_conversion.h"
+#include "chromeos/services/ime/public/proto/messages.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace ime {
+
+// EqualsProto must match against two arguments: a buffer containing the actual
+// serialized proto and a number indicating the size of the buffer.
+MATCHER_P(EqualsProto,
+          message,
+          "Match a proto Message equal to the matcher's argument.") {
+  std::string expected_serialized;
+  message.SerializeToString(&expected_serialized);
+
+  const char* bytes = reinterpret_cast<const char*>(std::get<0>(arg));
+  int size = std::get<1>(arg);
+  std::string actual_serialized(bytes, size);
+  return expected_serialized == actual_serialized;
+}
+
+constexpr char kImeSpec[] = "xkb:us::eng";
+
+class MockImeEngineMainEntry : public ImeEngineMainEntry {
+ public:
+  bool IsImeSupported(const char*) final { return true; }
+  bool ActivateIme(const char*, ImeClientDelegate* delegate) final {
+    delegate_ = delegate;
+    return true;
+  }
+  MOCK_METHOD(void, Process, (const uint8_t* data, size_t size));
+  void Destroy() final {}
+
+  ImeClientDelegate* delegate() const { return delegate_; }
+
+ private:
+  ImeClientDelegate* delegate_;
+};
+
+class StubInputChannel : public mojom::InputChannel {
+  void ProcessMessage(const std::vector<uint8_t>& message,
+                      ProcessMessageCallback callback) final {
+    std::move(callback).Run({});
+  }
+  void OnFocus() final {}
+  void ProcessKeypressForRulebased(
+      ime::mojom::PhysicalKeyEventPtr event,
+      ProcessKeypressForRulebasedCallback callback) final {}
+  void OnKeyEvent(ime::mojom::PhysicalKeyEventPtr event,
+                  OnKeyEventCallback callback) final {}
+  void ResetForRulebased() final {}
+  void GetRulebasedKeypressCountForTesting(
+      GetRulebasedKeypressCountForTestingCallback callback) final {}
+};
+
+// Sets up the test environment for Mojo and inject a mock ImeEngineMainEntry.
+class DecoderEngineTest : public testing::Test {
+ protected:
+  void SetUp() final { FakeEngineMainEntryForTesting(&mock_main_entry_); }
+
+  void TearDown() final { FakeEngineMainEntryForTesting(nullptr); }
+
+  MockImeEngineMainEntry mock_main_entry_;
+
+ private:
+  // Mojo calls need a SequencedTaskRunner.
+  base::test::SingleThreadTaskEnvironment task_environment;
+};
+
+TEST_F(DecoderEngineTest, BindRequestBindsInterfaces) {
+  DecoderEngine engine(/*platform=*/nullptr);
+
+  StubInputChannel stub_channel;
+  mojo::Receiver<mojom::InputChannel> receiver(&stub_channel);
+  mojo::Remote<mojom::InputChannel> client;
+  EXPECT_TRUE(engine.BindRequest(kImeSpec, client.BindNewPipeAndPassReceiver(),
+                                 receiver.BindNewPipeAndPassRemote(), {}));
+
+  EXPECT_TRUE(client.is_bound());
+  EXPECT_TRUE(receiver.is_bound());
+}
+
+TEST_F(DecoderEngineTest, OnFocusSendsMessageToSharedLib) {
+  DecoderEngine engine(/*platform=*/nullptr);
+  StubInputChannel stub_channel;
+  mojo::Receiver<mojom::InputChannel> receiver(&stub_channel);
+  mojo::Remote<mojom::InputChannel> client;
+  ASSERT_TRUE(engine.BindRequest(kImeSpec, client.BindNewPipeAndPassReceiver(),
+                                 receiver.BindNewPipeAndPassRemote(), {}));
+  ime::Wrapper expected_proto;
+  *expected_proto.mutable_public_message() = OnFocusToProto(/*seq_id=*/0);
+
+  EXPECT_CALL(mock_main_entry_, Process).With(EqualsProto(expected_proto));
+
+  client->OnFocus();
+  client.FlushForTesting();
+}
+
+TEST_F(DecoderEngineTest, OnKeyEventRepliesWithCallback) {
+  DecoderEngine engine(/*platform=*/nullptr);
+  StubInputChannel stub_channel;
+  mojo::Receiver<mojom::InputChannel> receiver(&stub_channel);
+  mojo::Remote<mojom::InputChannel> client;
+  ASSERT_TRUE(engine.BindRequest(kImeSpec, client.BindNewPipeAndPassReceiver(),
+                                 receiver.BindNewPipeAndPassRemote(), {}));
+  auto key_event = mojom::PhysicalKeyEvent::New(
+      mojom::KeyEventType::kKeyDown, "KeyA", "A", mojom::ModifierState::New());
+  ime::Wrapper expected_proto;
+  *expected_proto.mutable_public_message() =
+      OnKeyEventToProto(/*seq_id=*/0, key_event.Clone());
+
+  // Set up the mock shared library to reply to the key event.
+  bool consumed_by_test = false;
+  EXPECT_CALL(mock_main_entry_, Process)
+      .With(EqualsProto(expected_proto))
+      .WillOnce([this]() {
+        ime::Wrapper wrapper;
+        wrapper.mutable_public_message()
+            ->mutable_on_key_event_reply()
+            ->set_consumed(true);
+        std::vector<uint8_t> output(wrapper.ByteSizeLong());
+        wrapper.SerializeToArray(output.data(), output.size());
+        mock_main_entry_.delegate()->Process(output.data(), output.size());
+      });
+
+  client->OnKeyEvent(
+      std::move(key_event),
+      base::BindLambdaForTesting(
+          [&consumed_by_test](bool consumed) { consumed_by_test = consumed; }));
+  client.FlushForTesting();
+
+  EXPECT_TRUE(consumed_by_test);
+}
+
+}  // namespace ime
+}  // namespace chromeos
diff --git a/chromeos/services/ime/decoder/proto_conversion.cc b/chromeos/services/ime/decoder/proto_conversion.cc
new file mode 100644
index 0000000..6de939b
--- /dev/null
+++ b/chromeos/services/ime/decoder/proto_conversion.cc
@@ -0,0 +1,50 @@
+// 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 "chromeos/services/ime/decoder/proto_conversion.h"
+
+namespace chromeos {
+namespace ime {
+namespace {
+
+ModifierState ModifierStateToProto(mojom::ModifierStatePtr modifier_state) {
+  ModifierState result;
+  result.set_alt(modifier_state->alt);
+  result.set_alt_graph(modifier_state->alt_graph);
+  result.set_caps_lock(modifier_state->caps_lock);
+  result.set_control(modifier_state->control);
+  result.set_meta(modifier_state->meta);
+  result.set_shift(modifier_state->shift);
+  return result;
+}
+
+}  // namespace
+
+ime::PublicMessage OnFocusToProto(uint64_t seq_id) {
+  ime::PublicMessage message;
+  message.set_seq_id(seq_id);
+
+  *message.mutable_on_focus() = ime::OnFocus();
+  return message;
+}
+
+ime::PublicMessage OnKeyEventToProto(uint64_t seq_id,
+                                     mojom::PhysicalKeyEventPtr event) {
+  ime::PublicMessage message;
+  message.set_seq_id(seq_id);
+
+  ime::PhysicalKeyEvent& key_event =
+      *message.mutable_on_key_event()->mutable_key_event();
+  key_event.set_type(event->type == mojom::KeyEventType::kKeyDown
+                         ? ime::PhysicalKeyEvent::EVENT_TYPE_KEY_DOWN
+                         : ime::PhysicalKeyEvent::EVENT_TYPE_KEY_UP);
+  key_event.set_code(event->code);
+  key_event.set_key(event->key);
+  *key_event.mutable_modifier_state() =
+      ModifierStateToProto(std::move(event->modifier_state));
+  return message;
+}
+
+}  // namespace ime
+}  // namespace chromeos
diff --git a/chromeos/services/ime/decoder/proto_conversion.h b/chromeos/services/ime/decoder/proto_conversion.h
new file mode 100644
index 0000000..3e117216
--- /dev/null
+++ b/chromeos/services/ime/decoder/proto_conversion.h
@@ -0,0 +1,26 @@
+// 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 CHROMEOS_SERVICES_IME_DECODER_PROTO_CONVERSION_H_
+#define CHROMEOS_SERVICES_IME_DECODER_PROTO_CONVERSION_H_
+
+#include <vector>
+
+#include "chromeos/services/ime/public/mojom/input_engine.mojom.h"
+#include "chromeos/services/ime/public/proto/messages.pb.h"
+
+namespace chromeos {
+namespace ime {
+
+// Converts arguments of a Mojo call to InputChannel::OnFocus into a proto.
+ime::PublicMessage OnFocusToProto(uint64_t seq_id);
+
+// Converts arguments of a Mojo call to InputChannel::OnKeyEvent into a proto.
+ime::PublicMessage OnKeyEventToProto(uint64_t seq_id,
+                                     mojom::PhysicalKeyEventPtr event);
+
+}  // namespace ime
+}  // namespace chromeos
+
+#endif  // CHROMEOS_SERVICES_IME_DECODER_PROTO_CONVERSION_H_
diff --git a/chromeos/services/ime/decoder/proto_conversion_unittest.cc b/chromeos/services/ime/decoder/proto_conversion_unittest.cc
new file mode 100644
index 0000000..b945207
--- /dev/null
+++ b/chromeos/services/ime/decoder/proto_conversion_unittest.cc
@@ -0,0 +1,52 @@
+// 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 "chromeos/services/ime/decoder/proto_conversion.h"
+
+#include "chromeos/services/ime/public/proto/messages.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace ime {
+
+TEST(ProtoConversionTest, OnFocusToProto) {
+  ime::PublicMessage expected_message;
+  expected_message.set_seq_id(42);
+  *expected_message.mutable_on_focus() = ime::OnFocus();
+
+  ime::PublicMessage actual_message = OnFocusToProto(/*seq_id=*/42);
+
+  EXPECT_EQ(actual_message.SerializeAsString(),
+            expected_message.SerializeAsString());
+}
+
+TEST(ProtoConversionTest, OnKeyEventToProto) {
+  auto modifier_state = mojom::ModifierState::New();
+  modifier_state->shift = true;
+  auto key_event = mojom::PhysicalKeyEvent::New(
+      mojom::KeyEventType::kKeyDown, "KeyA", "A", std::move(modifier_state));
+
+  ime::PublicMessage expected_message;
+  expected_message.set_seq_id(42);
+  ime::OnKeyEvent& args = *expected_message.mutable_on_key_event();
+  args.mutable_key_event()->set_type(
+      ime::PhysicalKeyEvent::EVENT_TYPE_KEY_DOWN);
+  args.mutable_key_event()->set_code("KeyA");
+  args.mutable_key_event()->set_key("A");
+  args.mutable_key_event()->mutable_modifier_state()->set_alt(false);
+  args.mutable_key_event()->mutable_modifier_state()->set_alt_graph(false);
+  args.mutable_key_event()->mutable_modifier_state()->set_caps_lock(false);
+  args.mutable_key_event()->mutable_modifier_state()->set_control(false);
+  args.mutable_key_event()->mutable_modifier_state()->set_meta(false);
+  args.mutable_key_event()->mutable_modifier_state()->set_shift(true);
+
+  const ime::PublicMessage actual_message =
+      OnKeyEventToProto(/*seq_id=*/42, std::move(key_event));
+
+  EXPECT_EQ(actual_message.SerializeAsString(),
+            expected_message.SerializeAsString());
+}
+
+}  // namespace ime
+}  // namespace chromeos
diff --git a/chromeos/services/ime/ime_decoder.cc b/chromeos/services/ime/ime_decoder.cc
new file mode 100644
index 0000000..d20f47a2
--- /dev/null
+++ b/chromeos/services/ime/ime_decoder.cc
@@ -0,0 +1,79 @@
+// 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 "chromeos/services/ime/ime_decoder.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "chromeos/services/ime/constants.h"
+
+namespace chromeos {
+namespace ime {
+
+namespace {
+const char kCrosImeDecoderLib[] = "libimedecoder.so";
+
+// TODO(b/161491092): Add test image path based on value of
+// "CHROMEOS_RELEASE_TRACK" from `base::SysInfo::GetLsbReleaseValue`.
+// Returns ImeDecoderLib path based on the run time env.
+base::FilePath GetImeDecoderLibPath() {
+#if defined(__x86_64__) || defined(__aarch64__)
+  base::FilePath lib_path("/usr/lib64");
+#else
+  base::FilePath lib_path("/usr/lib");
+#endif
+  lib_path = lib_path.Append(kCrosImeDecoderLib);
+  return lib_path;
+}
+
+}  // namespace
+
+ImeDecoder::ImeDecoder() : status_(Status::kUninitialized) {
+  base::FilePath path = GetImeDecoderLibPath();
+
+  if (!base::PathExists(path)) {
+    LOG(WARNING) << "IME decoder shared library is not installed.";
+    status_ = Status::kNotInstalled;
+    return;
+  }
+
+  // Add dlopen flags (RTLD_LAZY | RTLD_NODELETE) later.
+  base::ScopedNativeLibrary library = base::ScopedNativeLibrary(path);
+  if (!library.is_valid()) {
+    LOG(ERROR) << "Failed to load decoder shared library from: " << path
+               << ", error: " << library.GetError()->ToString();
+    status_ = Status::kLoadLibraryFailed;
+    return;
+  }
+
+  createMainEntry_ = reinterpret_cast<ImeMainEntryCreateFn>(
+      library.GetFunctionPointer(IME_MAIN_ENTRY_CREATE_FN_NAME));
+  if (!createMainEntry_) {
+    status_ = Status::kFunctionMissing;
+    return;
+  }
+
+  library_ = std::move(library);
+  status_ = Status::kSuccess;
+}
+
+ImeDecoder::~ImeDecoder() = default;
+
+ImeDecoder* ImeDecoder::GetInstance() {
+  static base::NoDestructor<ImeDecoder> instance;
+  return instance.get();
+}
+
+ImeDecoder::Status ImeDecoder::GetStatus() const {
+  return status_;
+}
+
+ImeEngineMainEntry* ImeDecoder::CreateMainEntry(ImeCrosPlatform* platform) {
+  DCHECK(status_ == Status::kSuccess);
+  return createMainEntry_(platform);
+}
+
+}  // namespace ime
+}  // namespace chromeos
diff --git a/chromeos/services/ime/ime_decoder.h b/chromeos/services/ime/ime_decoder.h
new file mode 100644
index 0000000..90ace22
--- /dev/null
+++ b/chromeos/services/ime/ime_decoder.h
@@ -0,0 +1,60 @@
+// 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 CHROMEOS_SERVICES_IME_IME_DECODER_H_
+#define CHROMEOS_SERVICES_IME_IME_DECODER_H_
+
+#include "chromeos/services/ime/public/cpp/shared_lib/interfaces.h"
+
+#include "base/no_destructor.h"
+#include "base/optional.h"
+#include "base/scoped_native_library.h"
+
+namespace chromeos {
+namespace ime {
+
+// A proxy class for the IME decoder.
+// ImeDecoder is implemented as a singleton and is initialized before 'ime'
+// sandbox is engaged.
+class ImeDecoder {
+ public:
+  // Status of loading func from IME decoder DSO: either success or error type.
+  enum class Status {
+    kSuccess = 0,
+    kUninitialized = 1,
+    kNotInstalled = 2,
+    kLoadLibraryFailed = 3,
+    kFunctionMissing = 4,
+  };
+
+  // Gets the singleton ImeDecoder.
+  static ImeDecoder* GetInstance();
+
+  // Get status of the IME decoder library initialization.
+  // Return `Status::kSuccess` if the lib is successfully initialized.
+  Status GetStatus() const;
+
+  // Returns an instance of ImeEngineMainEntry from the IME shared library.
+  ImeEngineMainEntry* CreateMainEntry(ImeCrosPlatform* platform);
+
+ private:
+  friend class base::NoDestructor<ImeDecoder>;
+
+  // Initialize the Ime decoder library.
+  explicit ImeDecoder();
+  ~ImeDecoder();
+
+  Status status_;
+
+  // Result of IME decoder DSO initialization.
+  base::Optional<base::ScopedNativeLibrary> library_;
+  ImeMainEntryCreateFn createMainEntry_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImeDecoder);
+};
+
+}  // namespace ime
+}  // namespace chromeos
+
+#endif  // CHROMEOS_SERVICES_IME_IME_DECODER_H_
diff --git a/chromeos/services/ime/ime_sandbox_hook.cc b/chromeos/services/ime/ime_sandbox_hook.cc
index 052948c..c930ad4 100644
--- a/chromeos/services/ime/ime_sandbox_hook.cc
+++ b/chromeos/services/ime/ime_sandbox_hook.cc
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "build/buildflag.h"
 #include "chromeos/services/ime/constants.h"
+#include "chromeos/services/ime/ime_decoder.h"
 #include "chromeos/services/ime/public/cpp/buildflags.h"
 #include "sandbox/linux/syscall_broker/broker_command.h"
 #include "sandbox/linux/syscall_broker/broker_file_permission.h"
@@ -32,16 +33,6 @@
 #endif
 }
 
-constexpr int dlopen_flag = RTLD_LAZY | RTLD_NODELETE;
-
-void PreloadSharedLibrary() {
-  if (ImeDecoderInstalled()) {
-    if (!dlopen(kCrosImeDecoderLib, dlopen_flag))
-      LOG(ERROR) << "Unable to open " << kCrosImeDecoderLib << " : "
-                 << dlerror();
-  }
-}
-
 void AddBundleFolder(std::vector<BrokerFilePermission>* permissions) {
   base::FilePath bundle_dir =
       base::FilePath(kBundledInputMethodsDirPath).AsEndingWithSeparator();
@@ -86,7 +77,6 @@
       BrokerFilePermission::ReadOnly("/dev/urandom"),
       BrokerFilePermission::ReadOnly("/sys/devices/system/cpu")};
 
-  PreloadSharedLibrary();
   AddBundleFolder(&permissions);
   AddUserDataFolder(&permissions);
   AddSharedDataFolderIfEnabled(&permissions);
@@ -110,6 +100,8 @@
                                sandbox::policy::SandboxLinux::PreSandboxHook(),
                                options);
 
+  // Try to load IME decoder shared library by creating its instance.
+  ImeDecoder::GetInstance();
   instance->EngageNamespaceSandboxIfPossible();
   return true;
 }
diff --git a/chromeos/services/ime/ime_service_unittest.cc b/chromeos/services/ime/ime_service_unittest.cc
index fa19942..10c17b6 100644
--- a/chromeos/services/ime/ime_service_unittest.cc
+++ b/chromeos/services/ime/ime_service_unittest.cc
@@ -59,6 +59,9 @@
   MOCK_METHOD2(ProcessKeypressForRulebased,
                void(const mojom::PhysicalKeyEventPtr event,
                     ProcessKeypressForRulebasedCallback));
+  MOCK_METHOD2(OnKeyEvent,
+               void(const mojom::PhysicalKeyEventPtr event,
+                    OnKeyEventCallback));
   MOCK_METHOD0(ResetForRulebased, void());
   MOCK_METHOD1(GetRulebasedKeypressCountForTesting,
                void(GetRulebasedKeypressCountForTestingCallback));
diff --git a/chromeos/services/ime/input_engine.cc b/chromeos/services/ime/input_engine.cc
index 2358bc1..ee0eaee5 100644
--- a/chromeos/services/ime/input_engine.cc
+++ b/chromeos/services/ime/input_engine.cc
@@ -153,6 +153,11 @@
   std::move(callback).Run(std::move(keypress_response));
 }
 
+void InputEngine::OnKeyEvent(mojom::PhysicalKeyEventPtr event,
+                             OnKeyEventCallback callback) {
+  NOTIMPLEMENTED();  // Not used in the rulebased engine.
+}
+
 void InputEngine::ResetForRulebased() {
   auto& context = channel_receivers_.current_context();
   auto& engine = context.get()->engine;
diff --git a/chromeos/services/ime/input_engine.h b/chromeos/services/ime/input_engine.h
index 9002db5..7d08d9e 100644
--- a/chromeos/services/ime/input_engine.h
+++ b/chromeos/services/ime/input_engine.h
@@ -30,6 +30,7 @@
 };
 
 // A basic implementation of InputEngine without using any decoder.
+// TODO(https://crbug.com/1019541): Rename this to RuleBasedEngine.
 class InputEngine : public mojom::InputChannel {
  public:
   InputEngine();
@@ -49,6 +50,8 @@
   void ProcessKeypressForRulebased(
       mojom::PhysicalKeyEventPtr event,
       ProcessKeypressForRulebasedCallback callback) override;
+  void OnKeyEvent(mojom::PhysicalKeyEventPtr event,
+                  OnKeyEventCallback callback) override;
   void ResetForRulebased() override;
   void GetRulebasedKeypressCountForTesting(
       GetRulebasedKeypressCountForTestingCallback callback) override;
diff --git a/chromeos/services/ime/public/mojom/input_engine.mojom b/chromeos/services/ime/public/mojom/input_engine.mojom
index 85417d8e..11f29dc 100644
--- a/chromeos/services/ime/public/mojom/input_engine.mojom
+++ b/chromeos/services/ime/public/mojom/input_engine.mojom
@@ -115,6 +115,9 @@
   // Called when there's a new focused input field.
   OnFocus();
 
+  // Process a PhysicalKeyEvent for non-rule-based engines.
+  OnKeyEvent(PhysicalKeyEvent event) => (bool consumed);
+
   // Process a PhysicalKeyEvent using the rule-based engine and return a
   // KeypressResponseForRulebased object with a list of operations to be handled
   // by the caller.
diff --git a/chromeos/services/ime/public/proto/messages.proto b/chromeos/services/ime/public/proto/messages.proto
index 2d39127e..861797b34 100644
--- a/chromeos/services/ime/public/proto/messages.proto
+++ b/chromeos/services/ime/public/proto/messages.proto
@@ -28,7 +28,11 @@
 message PublicMessage {
   optional int32 seq_id = 1;
 
-  oneof param { OnFocus on_focus = 2; }
+  oneof param {
+    OnFocus on_focus = 2;
+    OnKeyEvent on_key_event = 3;
+    OnKeyEventReply on_key_event_reply = 4;
+  }
 }
 
 // Protobuf version of InputEngine::OnFocus in
@@ -36,3 +40,41 @@
 message OnFocus {
   // TODO(crbug/1019541): Add information about the input field.
 }
+
+// Protobuf version of InputEngine::OnKeyEvent in
+// chromeos/services/ime/public/mojom/input_engine.mojom
+message OnKeyEvent {
+  optional PhysicalKeyEvent key_event = 1;
+}
+
+// Protobuf version of the reply from InputEngine::OnKeyEvent in
+// chromeos/services/ime/public/mojom/input_engine.mojom
+message OnKeyEventReply {
+  optional bool consumed = 1;
+}
+
+// Protobuf version of InputEngine::PhysicalKeyEvent in
+// chromeos/services/ime/public/mojom/input_engine.mojom
+message PhysicalKeyEvent {
+  enum EventType {
+    EVENT_TYPE_UNSPECIFIED = 0;
+    EVENT_TYPE_KEY_DOWN = 1;
+    EVENT_TYPE_KEY_UP = 2;
+  }
+
+  optional EventType type = 1;
+  optional string code = 2;
+  optional string key = 3;
+  optional ModifierState modifier_state = 4;
+}
+
+// Protobuf version of InputEngine::PhysicalKeyEvent in
+// chromeos/services/ime/public/mojom/input_engine.mojom
+message ModifierState {
+  optional bool alt = 1;
+  optional bool alt_graph = 2;
+  optional bool caps_lock = 3;
+  optional bool control = 4;
+  optional bool meta = 5;
+  optional bool shift = 6;
+}
diff --git a/chromeos/ui/frame/caption_buttons/frame_back_button.cc b/chromeos/ui/frame/caption_buttons/frame_back_button.cc
index f2b9041..2981cb80 100644
--- a/chromeos/ui/frame/caption_buttons/frame_back_button.cc
+++ b/chromeos/ui/frame/caption_buttons/frame_back_button.cc
@@ -18,7 +18,10 @@
 namespace chromeos {
 
 FrameBackButton::FrameBackButton()
-    : FrameCaptionButton(this, views::CAPTION_BUTTON_ICON_BACK, HTMENU) {
+    : FrameCaptionButton(base::BindRepeating(&FrameBackButton::ButtonPressed,
+                                             base::Unretained(this)),
+                         views::CAPTION_BUTTON_ICON_BACK,
+                         HTMENU) {
   SetPreferredSize(views::GetCaptionButtonLayoutSize(
       views::CaptionButtonLayoutSize::kNonBrowserCaption));
   SetAccessibleName(l10n_util::GetStringUTF16(IDS_APP_ACCNAME_BACK));
@@ -26,7 +29,7 @@
 
 FrameBackButton::~FrameBackButton() = default;
 
-void FrameBackButton::ButtonPressed(Button* sender, const ui::Event& event) {
+void FrameBackButton::ButtonPressed() {
   // Send up event as well as down event as ARC++ clients expect this sequence.
   // TODO: Investigate if we should be using the current modifiers.
   aura::Window* root_window = GetWidget()->GetNativeWindow()->GetRootWindow();
diff --git a/chromeos/ui/frame/caption_buttons/frame_back_button.h b/chromeos/ui/frame/caption_buttons/frame_back_button.h
index 331de34..97c279f 100644
--- a/chromeos/ui/frame/caption_buttons/frame_back_button.h
+++ b/chromeos/ui/frame/caption_buttons/frame_back_button.h
@@ -13,16 +13,14 @@
 // A button to send back key events. It's used in Chrome hosted app windows,
 // among other places.
 class COMPONENT_EXPORT(CHROMEOS_UI_FRAME) FrameBackButton
-    : public views::FrameCaptionButton,
-      public views::ButtonListener {
+    : public views::FrameCaptionButton {
  public:
   FrameBackButton();
   ~FrameBackButton() override;
 
-  // views::ButtonListener:
-  void ButtonPressed(Button* sender, const ui::Event& event) override;
-
  private:
+  void ButtonPressed();
+
   DISALLOW_COPY_AND_ASSIGN(FrameBackButton);
 };
 
diff --git a/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc
index 59db93c..d47a4d2 100644
--- a/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc
+++ b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc
@@ -177,23 +177,33 @@
 
   // Insert the buttons left to right.
   menu_button_ = new views::FrameCaptionButton(
-      this, views::CAPTION_BUTTON_ICON_MENU, HTMENU);
+      base::BindRepeating(&FrameCaptionButtonContainerView::MenuButtonPressed,
+                          base::Unretained(this)),
+      views::CAPTION_BUTTON_ICON_MENU, HTMENU);
   menu_button_->SetTooltipText(l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MENU));
   AddChildView(menu_button_);
 
   minimize_button_ = new views::FrameCaptionButton(
-      this, views::CAPTION_BUTTON_ICON_MINIMIZE, HTMINBUTTON);
+      base::BindRepeating(
+          &FrameCaptionButtonContainerView::MinimizeButtonPressed,
+          base::Unretained(this)),
+      views::CAPTION_BUTTON_ICON_MINIMIZE, HTMINBUTTON);
   minimize_button_->SetTooltipText(
       l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE));
   AddChildView(minimize_button_);
 
-  size_button_ = new FrameSizeButton(this, this);
+  size_button_ = new FrameSizeButton(
+      base::BindRepeating(&FrameCaptionButtonContainerView::SizeButtonPressed,
+                          base::Unretained(this)),
+      this);
   size_button_->SetTooltipText(
       l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE));
   AddChildView(size_button_);
 
   close_button_ = new views::FrameCaptionButton(
-      this, views::CAPTION_BUTTON_ICON_CLOSE, HTCLOSE);
+      base::BindRepeating(&FrameCaptionButtonContainerView::CloseButtonPressed,
+                          base::Unretained(this)),
+      views::CAPTION_BUTTON_ICON_CLOSE, HTCLOSE);
   close_button_->SetTooltipText(
       l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE));
   AddChildView(close_button_);
@@ -397,49 +407,59 @@
     button->SetImage(icon, fcb_animate, *it->second);
 }
 
-void FrameCaptionButtonContainerView::ButtonPressed(views::Button* sender,
-                                                    const ui::Event& event) {
+void FrameCaptionButtonContainerView::MinimizeButtonPressed() {
   // Abort any animations of the button icons.
   SetButtonsToNormal(ANIMATE_NO);
 
-  using base::RecordAction;
-  using base::UserMetricsAction;
-  if (sender == minimize_button_) {
-    frame_->Minimize();
-    RecordAction(UserMetricsAction("MinButton_Clk"));
-  } else if (sender == size_button_) {
-    if (frame_->IsFullscreen()) {  // Can be clicked in immersive fullscreen.
-      frame_->Restore();
-      RecordAction(UserMetricsAction("MaxButton_Clk_ExitFS"));
-    } else if (frame_->IsMaximized()) {
-      frame_->Restore();
-      RecordAction(UserMetricsAction("MaxButton_Clk_Restore"));
-    } else {
-      frame_->Maximize();
-      RecordAction(UserMetricsAction("MaxButton_Clk_Maximize"));
-    }
-  } else if (sender == close_button_) {
-    frame_->Close();
-    if (chromeos::TabletState::Get()->InTabletMode())
-      RecordAction(UserMetricsAction("Tablet_WindowCloseFromCaptionButton"));
-    else
-      RecordAction(UserMetricsAction("CloseButton_Clk"));
-  } else if (sender == menu_button_) {
-    // Send up event as well as down event as ARC++ clients expect this
-    // sequence.
-    aura::Window* root_window = GetWidget()->GetNativeWindow()->GetRootWindow();
-    ui::KeyEvent press_key_event(ui::ET_KEY_PRESSED, ui::VKEY_APPS,
-                                 ui::EF_NONE);
-    ignore_result(root_window->GetHost()->event_sink()->OnEventFromSource(
-        &press_key_event));
-    ui::KeyEvent release_key_event(ui::ET_KEY_RELEASED, ui::VKEY_APPS,
-                                   ui::EF_NONE);
-    ignore_result(root_window->GetHost()->event_sink()->OnEventFromSource(
-        &release_key_event));
-    // TODO(oshima): Add metrics
+  frame_->Minimize();
+  base::RecordAction(base::UserMetricsAction("MinButton_Clk"));
+}
+
+void FrameCaptionButtonContainerView::SizeButtonPressed() {
+  // Abort any animations of the button icons.
+  SetButtonsToNormal(ANIMATE_NO);
+
+  if (frame_->IsFullscreen()) {  // Can be clicked in immersive fullscreen.
+    frame_->Restore();
+    base::RecordAction(base::UserMetricsAction("MaxButton_Clk_ExitFS"));
+  } else if (frame_->IsMaximized()) {
+    frame_->Restore();
+    base::RecordAction(base::UserMetricsAction("MaxButton_Clk_Restore"));
+  } else {
+    frame_->Maximize();
+    base::RecordAction(base::UserMetricsAction("MaxButton_Clk_Maximize"));
   }
 }
 
+void FrameCaptionButtonContainerView::CloseButtonPressed() {
+  // Abort any animations of the button icons.
+  SetButtonsToNormal(ANIMATE_NO);
+
+  frame_->Close();
+  if (chromeos::TabletState::Get()->InTabletMode()) {
+    base::RecordAction(
+        base::UserMetricsAction("Tablet_WindowCloseFromCaptionButton"));
+  } else {
+    base::RecordAction(base::UserMetricsAction("CloseButton_Clk"));
+  }
+}
+
+void FrameCaptionButtonContainerView::MenuButtonPressed() {
+  // Abort any animations of the button icons.
+  SetButtonsToNormal(ANIMATE_NO);
+
+  // Send up event as well as down event as ARC++ clients expect this sequence.
+  aura::Window* root_window = GetWidget()->GetNativeWindow()->GetRootWindow();
+  ui::KeyEvent press_key_event(ui::ET_KEY_PRESSED, ui::VKEY_APPS, ui::EF_NONE);
+  ignore_result(root_window->GetHost()->event_sink()->OnEventFromSource(
+      &press_key_event));
+  ui::KeyEvent release_key_event(ui::ET_KEY_RELEASED, ui::VKEY_APPS,
+                                 ui::EF_NONE);
+  ignore_result(root_window->GetHost()->event_sink()->OnEventFromSource(
+      &release_key_event));
+  // TODO(oshima): Add metrics
+}
+
 bool FrameCaptionButtonContainerView::IsMinimizeButtonVisible() const {
   return minimize_button_->GetVisible();
 }
diff --git a/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h
index bff904e..26d70111 100644
--- a/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h
+++ b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h
@@ -13,7 +13,6 @@
 #include "chromeos/ui/frame/caption_buttons/frame_size_button_delegate.h"
 #include "chromeos/ui/frame/caption_buttons/snap_controller.h"
 #include "ui/views/animation/animation_delegate_views.h"
-#include "ui/views/controls/button/button.h"
 #include "ui/views/view.h"
 #include "ui/views/window/frame_caption_button.h"
 
@@ -36,7 +35,6 @@
 // utilities).
 class COMPONENT_EXPORT(CHROMEOS_UI_FRAME) FrameCaptionButtonContainerView
     : public views::View,
-      public views::ButtonListener,
       public FrameSizeButtonDelegate,
       public views::AnimationDelegateViews {
  public:
@@ -128,8 +126,10 @@
                      views::CaptionButtonIcon icon,
                      Animate animate);
 
-  // views::ButtonListener:
-  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+  void MinimizeButtonPressed();
+  void SizeButtonPressed();
+  void CloseButtonPressed();
+  void MenuButtonPressed();
 
   // FrameSizeButtonDelegate:
   bool IsMinimizeButtonVisible() const override;
diff --git a/chromeos/ui/frame/caption_buttons/frame_size_button.cc b/chromeos/ui/frame/caption_buttons/frame_size_button.cc
index 7a1e1d58..f0b1b6e9 100644
--- a/chromeos/ui/frame/caption_buttons/frame_size_button.cc
+++ b/chromeos/ui/frame/caption_buttons/frame_size_button.cc
@@ -111,9 +111,9 @@
   DISALLOW_COPY_AND_ASSIGN(SnappingWindowObserver);
 };
 
-FrameSizeButton::FrameSizeButton(views::ButtonListener* listener,
+FrameSizeButton::FrameSizeButton(PressedCallback callback,
                                  FrameSizeButtonDelegate* delegate)
-    : views::FrameCaptionButton(listener,
+    : views::FrameCaptionButton(std::move(callback),
                                 views::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE,
                                 HTMAXBUTTON),
       delegate_(delegate),
diff --git a/chromeos/ui/frame/caption_buttons/frame_size_button.h b/chromeos/ui/frame/caption_buttons/frame_size_button.h
index 893946f..6b76277 100644
--- a/chromeos/ui/frame/caption_buttons/frame_size_button.h
+++ b/chromeos/ui/frame/caption_buttons/frame_size_button.h
@@ -27,8 +27,7 @@
 class COMPONENT_EXPORT(CHROMEOS_UI_FRAME) FrameSizeButton
     : public views::FrameCaptionButton {
  public:
-  FrameSizeButton(views::ButtonListener* listener,
-                  FrameSizeButtonDelegate* delegate);
+  FrameSizeButton(PressedCallback callback, FrameSizeButtonDelegate* delegate);
 
   ~FrameSizeButton() override;
 
diff --git a/components/arc/metrics/arc_metrics_service.cc b/components/arc/metrics/arc_metrics_service.cc
index a3a2454..45567c01 100644
--- a/components/arc/metrics/arc_metrics_service.cc
+++ b/components/arc/metrics/arc_metrics_service.cc
@@ -136,6 +136,12 @@
   arc_bridge_service_->RemoveObserver(&arc_bridge_service_observer_);
 }
 
+void ArcMetricsService::Shutdown() {
+  for (auto& obs : app_kill_observers_)
+    obs.OnArcMetricsServiceDestroyed();
+  app_kill_observers_.Clear();
+}
+
 void ArcMetricsService::SetHistogramNamer(HistogramNamer histogram_namer) {
   histogram_namer_ = histogram_namer;
 }
@@ -273,6 +279,28 @@
   UMA_HISTOGRAM_ENUMERATION("Arc.CompanionLibraryApisCounter", api_id);
 }
 
+void ArcMetricsService::ReportAppKill(mojom::AppKillPtr app_kill) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  switch (app_kill->type) {
+    case mojom::AppKillType::LMKD_KILL:
+      NotifyLowMemoryKill();
+      break;
+    case mojom::AppKillType::OOM_KILL:
+      NotifyOOMKillCount(app_kill->count);
+      break;
+  }
+}
+
+void ArcMetricsService::NotifyLowMemoryKill() {
+  for (auto& obs : app_kill_observers_)
+    obs.OnArcLowMemoryKill();
+}
+
+void ArcMetricsService::NotifyOOMKillCount(unsigned long count) {
+  for (auto& obs : app_kill_observers_)
+    obs.OnArcOOMKillCount(count);
+}
+
 void ArcMetricsService::OnWindowActivated(
     wm::ActivationChangeObserver::ActivationReason reason,
     aura::Window* gained_active,
@@ -315,6 +343,15 @@
   guest_os_engagement_metrics_.SetBackgroundActive(!task_ids_.empty());
 }
 
+void ArcMetricsService::AddAppKillObserver(AppKillObserver* obs) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  app_kill_observers_.AddObserver(obs);
+}
+
+void ArcMetricsService::RemoveAppKillObserver(AppKillObserver* obs) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  app_kill_observers_.RemoveObserver(obs);
+}
 ArcMetricsService::ProcessObserver::ProcessObserver(
     ArcMetricsService* arc_metrics_service)
     : arc_metrics_service_(arc_metrics_service) {}
diff --git a/components/arc/metrics/arc_metrics_service.h b/components/arc/metrics/arc_metrics_service.h
index 736d260..786476e9 100644
--- a/components/arc/metrics/arc_metrics_service.h
+++ b/components/arc/metrics/arc_metrics_service.h
@@ -11,6 +11,8 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "base/optional.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
@@ -50,6 +52,13 @@
   using HistogramNamer =
       base::RepeatingCallback<std::string(const std::string& base_name)>;
 
+  class AppKillObserver : public base::CheckedObserver {
+   public:
+    virtual void OnArcLowMemoryKill() = 0;
+    virtual void OnArcOOMKillCount(unsigned long count) = 0;
+    virtual void OnArcMetricsServiceDestroyed() {}
+  };
+
   // Returns singleton instance for the given BrowserContext,
   // or nullptr if the browser |context| is not allowed to use ARC.
   static ArcMetricsService* GetForBrowserContext(
@@ -64,6 +73,9 @@
                     ArcBridgeService* bridge_service);
   ~ArcMetricsService() override;
 
+  // KeyedService overrides.
+  void Shutdown() override;
+
   // Sets the histogram namer. Required to not have a dependency on browser
   // codebase.
   void SetHistogramNamer(HistogramNamer histogram_namer);
@@ -77,6 +89,7 @@
                           mojom::BootType boot_type) override;
   void ReportNativeBridge(mojom::NativeBridgeType native_bridge_type) override;
   void ReportCompanionLibApiUsage(mojom::CompanionLibApiId api_id) override;
+  void ReportAppKill(mojom::AppKillPtr app_kill) override;
 
   // wm::ActivationChangeObserver overrides.
   // Records to UMA when a user has interacted with an ARC app window.
@@ -95,6 +108,9 @@
                      const std::string& intent);
   void OnTaskDestroyed(int32_t task_id);
 
+  void AddAppKillObserver(AppKillObserver* obs);
+  void RemoveAppKillObserver(AppKillObserver* obs);
+
  private:
   // Adapter to be able to also observe ProcessInstance events.
   class ProcessObserver : public ConnectionObserver<mojom::ProcessInstance> {
@@ -170,6 +186,10 @@
                                mojom::BootType boot_type,
                                base::Optional<base::TimeTicks> arc_start_time);
 
+  // Notify AppKillObservers.
+  void NotifyLowMemoryKill();
+  void NotifyOOMKillCount(unsigned long count);
+
   THREAD_CHECKER(thread_checker_);
 
   ArcBridgeService* const arc_bridge_service_;  // Owned by ArcServiceManager.
@@ -193,6 +213,8 @@
 
   bool gamepad_interaction_recorded_ = false;
 
+  base::ObserverList<AppKillObserver> app_kill_observers_;
+
   // Always keep this the last member of this class to make sure it's the
   // first thing to be destructed.
   base::WeakPtrFactory<ArcMetricsService> weak_ptr_factory_{this};
diff --git a/components/arc/mojom/metrics.mojom b/components/arc/mojom/metrics.mojom
index 5de9ef7..e8b7a4a 100644
--- a/components/arc/mojom/metrics.mojom
+++ b/components/arc/mojom/metrics.mojom
@@ -1,7 +1,7 @@
 // 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.
-// Next MinVersion: 6
+// Next MinVersion: 7
 
 module arc.mojom;
 
@@ -103,7 +103,23 @@
   IS_CLIPPING_TO_TASK_DISABLED = 23,
 };
 
-// Next method ID: 3
+// Describes the type of app kill being reported.
+[Extensible]
+enum AppKillType {
+  LMKD_KILL = 0,
+  OOM_KILL = 1,
+};
+
+// Describes an app kill from ARC instance.
+struct AppKill {
+  // Type of kill being reported.
+  AppKillType type;
+  // Number of kills. For LMKD kills, this is always 1. For OOM kills, this is
+  // the total oom_kill count from /proc/vm_stat.
+  uint32 count;
+};
+
+// Next method ID: 4
 interface MetricsHost {
   // Reports boot progress events from ARC instance.
   ReportBootProgress@0(array<BootProgressEvent> events,
@@ -114,6 +130,9 @@
 
   // Reports api usage by ChromeOS Companion Library.
   [MinVersion=4] ReportCompanionLibApiUsage@2(CompanionLibApiId api_id);
+
+  // Reports LMKD and OOM kills from ARC.
+  [MinVersion=6] ReportAppKill@3(AppKill app_kill);
 };
 
 // Next method ID: 3
diff --git a/components/paint_preview/browser/paint_preview_client.cc b/components/paint_preview/browser/paint_preview_client.cc
index 68db488b..212956c 100644
--- a/components/paint_preview/browser/paint_preview_client.cc
+++ b/components/paint_preview/browser/paint_preview_client.cc
@@ -275,6 +275,7 @@
     const PaintPreviewParams& params,
     content::RenderFrameHost* render_frame_host,
     PaintPreviewCallback callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (base::Contains(all_document_data_, params.inner.document_guid)) {
     std::move(callback).Run(params.inner.document_guid,
                             mojom::PaintPreviewStatus::kGuidCollision, {});
diff --git a/components/prerender/OWNERS b/components/prerender/OWNERS
index 705d4d5..559aefc1 100644
--- a/components/prerender/OWNERS
+++ b/components/prerender/OWNERS
@@ -1,3 +1,5 @@
+falken@chromium.org
+nhiroki@chromium.org
 robertogden@chromium.org
 ryansturm@chromium.org
 tbansal@chromium.org
diff --git a/components/search_engines/search_terms_data.cc b/components/search_engines/search_terms_data.cc
index 830f47f..0005ed8 100644
--- a/components/search_engines/search_terms_data.cc
+++ b/components/search_engines/search_terms_data.cc
@@ -46,7 +46,7 @@
   return std::string();
 }
 
-std::string SearchTermsData::GetSuggestClient() const {
+std::string SearchTermsData::GetSuggestClient(bool from_ntp) const {
   return std::string();
 }
 
diff --git a/components/search_engines/search_terms_data.h b/components/search_engines/search_terms_data.h
index 5f399b2..6fc3074 100644
--- a/components/search_engines/search_terms_data.h
+++ b/components/search_engines/search_terms_data.h
@@ -40,8 +40,9 @@
 
   // The suggest client parameter ("client") passed with Google suggest
   // requests.  See GetSuggestRequestIdentifier() for more details.
+  // |from_ntp| is true if the search is made from a non-searchbox NTP surface.
   // This implementation returns the empty string.
-  virtual std::string GetSuggestClient() const;
+  virtual std::string GetSuggestClient(bool from_ntp) const;
 
   // The suggest request identifier parameter ("gs_ri") passed with Google
   // suggest requests.   Along with suggestclient (See GetSuggestClient()),
diff --git a/components/search_engines/template_url.cc b/components/search_engines/template_url.cc
index 2a4c441..b096bd0 100644
--- a/components/search_engines/template_url.cc
+++ b/components/search_engines/template_url.cc
@@ -1118,7 +1118,7 @@
         // empty string.  (If we don't handle this case, we hit a
         // NOTREACHED below.)
         base::string16 rlz_string = search_terms_data.GetRlzParameterValue(
-            search_terms_args.from_app_list);
+            search_terms_args.request_source == CROS_APP_LIST);
         if (!rlz_string.empty()) {
           HandleReplacement("rlz", base::UTF16ToUTF8(rlz_string), *i, &url);
         }
@@ -1152,7 +1152,10 @@
 
       case GOOGLE_SUGGEST_CLIENT:
         HandleReplacement(
-            std::string(), search_terms_data.GetSuggestClient(), *i, &url);
+            std::string(),
+            search_terms_data.GetSuggestClient(
+                search_terms_args.request_source == NON_SEARCHBOX_NTP),
+            *i, &url);
         break;
 
       case GOOGLE_SUGGEST_REQUEST_ID:
diff --git a/components/search_engines/template_url.h b/components/search_engines/template_url.h
index 4a656ef..c65d09d 100644
--- a/components/search_engines/template_url.h
+++ b/components/search_engines/template_url.h
@@ -68,6 +68,13 @@
   // the |post_data|. See http://tools.ietf.org/html/rfc2046 for the details.
   typedef std::pair<std::string, std::string> PostContent;
 
+  // Enumeration of the known search or suggest request sources.
+  enum RequestSource {
+    SEARCHBOX,          // Omnibox or the NTP realbox. The default.
+    CROS_APP_LIST,      // Chrome OS app list search box.
+    NON_SEARCHBOX_NTP,  // Non-searchbox NTP surfaces.
+  };
+
   // This struct encapsulates arguments passed to
   // TemplateURLRef::ReplaceSearchTerms methods.  By default, only search_terms
   // is required and is passed in the constructor.
@@ -228,9 +235,8 @@
     // When searching for an image, the original size of the image.
     gfx::Size image_original_size;
 
-    // True if the search was made using the app list search box. Otherwise, the
-    // search was made using the omnibox.
-    bool from_app_list = false;
+    // Source of the search or suggest request.
+    RequestSource request_source = SEARCHBOX;
 
     ContextualSearchParams contextual_search_params;
   };
diff --git a/components/search_engines/template_url_unittest.cc b/components/search_engines/template_url_unittest.cc
index 78962a03b..1f0b8eb 100644
--- a/components/search_engines/template_url_unittest.cc
+++ b/components/search_engines/template_url_unittest.cc
@@ -891,7 +891,7 @@
   EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
   ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
   TemplateURLRef::SearchTermsArgs args(ASCIIToUTF16("x"));
-  args.from_app_list = true;
+  args.request_source = TemplateURLRef::CROS_APP_LIST;
   GURL result(url.url_ref().ReplaceSearchTerms(args, search_terms_data_));
   ASSERT_TRUE(result.is_valid());
   EXPECT_EQ("http://bar/?rlz=" + base::UTF16ToUTF8(rlz_string) + "&x",
@@ -1126,6 +1126,42 @@
   EXPECT_EQ("http://google.com/?foobar&client=search_client&", result_2.spec());
 }
 
+TEST_F(TemplateURLTest, SuggestClient) {
+  const std::string base_url_str("http://google.com/?");
+  const std::string query_params_str("client={google:suggestClient}");
+  const std::string full_url_str = base_url_str + query_params_str;
+  search_terms_data_.set_google_base_url(base_url_str);
+
+  TemplateURLData data;
+  data.SetURL(full_url_str);
+  TemplateURL url(data);
+  EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
+  ASSERT_FALSE(url.url_ref().SupportsReplacement(search_terms_data_));
+  TemplateURLRef::SearchTermsArgs search_terms_args;
+
+  // Check that the URL is correct when a client is not present.
+  GURL result(
+      url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_));
+  ASSERT_TRUE(result.is_valid());
+  EXPECT_EQ("http://google.com/?client=", result.spec());
+
+  // Check that the URL is correct when a client is present.
+  search_terms_data_.set_suggest_client("suggest_client");
+  GURL result_2(
+      url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_));
+  ASSERT_TRUE(result_2.is_valid());
+  EXPECT_EQ("http://google.com/?client=suggest_client", result_2.spec());
+
+  // Check that the URL is correct when a suggest request is made from a
+  // non-searchbox NTP surface.
+  search_terms_args.request_source = TemplateURLRef::NON_SEARCHBOX_NTP;
+  GURL result_3(
+      url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_));
+  ASSERT_TRUE(result_3.is_valid());
+  EXPECT_EQ("http://google.com/?client=suggest_client_from_ntp",
+            result_3.spec());
+}
+
 TEST_F(TemplateURLTest, GetURLNoSuggestionsURL) {
   TemplateURLData data;
   data.SetURL("http://google.com/?q={searchTerms}");
diff --git a/components/search_engines/testing_search_terms_data.cc b/components/search_engines/testing_search_terms_data.cc
index ac476a04..dea429b 100644
--- a/components/search_engines/testing_search_terms_data.cc
+++ b/components/search_engines/testing_search_terms_data.cc
@@ -27,6 +27,10 @@
   return search_client_;
 }
 
+std::string TestingSearchTermsData::GetSuggestClient(bool from_ntp) const {
+  return from_ntp ? suggest_client_ + "_from_ntp" : suggest_client_;
+}
+
 std::string TestingSearchTermsData::GoogleImageSearchSource() const {
   return "google_image_search_source";
 }
diff --git a/components/search_engines/testing_search_terms_data.h b/components/search_engines/testing_search_terms_data.h
index 2e21f2e..e7cc2be 100644
--- a/components/search_engines/testing_search_terms_data.h
+++ b/components/search_engines/testing_search_terms_data.h
@@ -16,6 +16,7 @@
   std::string GoogleBaseURLValue() const override;
   base::string16 GetRlzParameterValue(bool from_app_list) const override;
   std::string GetSearchClient() const override;
+  std::string GetSuggestClient(bool from_ntp) const override;
   std::string GoogleImageSearchSource() const override;
 
   // Estimates dynamic memory usage.
@@ -28,10 +29,14 @@
   void set_search_client(const std::string& search_client) {
     search_client_ = search_client;
   }
+  void set_suggest_client(const std::string& suggest_client) {
+    suggest_client_ = suggest_client;
+  }
 
  private:
   std::string google_base_url_;
   std::string search_client_;
+  std::string suggest_client_;
 
   DISALLOW_COPY_AND_ASSIGN(TestingSearchTermsData);
 };
diff --git a/content/browser/media/capture/web_contents_tracker.cc b/content/browser/media/capture/web_contents_tracker.cc
index f51484edb..486914a 100644
--- a/content/browser/media/capture/web_contents_tracker.cc
+++ b/content/browser/media/capture/web_contents_tracker.cc
@@ -171,14 +171,4 @@
   OnPossibleTargetChange(true);
 }
 
-void WebContentsTracker::DidShowFullscreenWidget() {
-  DVLOG(1) << "DidShowFullscreenWidget()";
-  OnPossibleTargetChange(false);
-}
-
-void WebContentsTracker::DidDestroyFullscreenWidget() {
-  DVLOG(1) << "DidDestroyFullscreenWidget()";
-  OnPossibleTargetChange(false);
-}
-
 }  // namespace content
diff --git a/content/browser/media/capture/web_contents_tracker.h b/content/browser/media/capture/web_contents_tracker.h
index 99bb394..c72de23 100644
--- a/content/browser/media/capture/web_contents_tracker.h
+++ b/content/browser/media/capture/web_contents_tracker.h
@@ -108,11 +108,6 @@
   // has been permanently lost.
   void WebContentsDestroyed() final;
 
-  // WebContentsObserver overrides to notify the client that the capture target
-  // may have changed due to a separate fullscreen widget shown/destroyed.
-  void DidShowFullscreenWidget() final;
-  void DidDestroyFullscreenWidget() final;
-
   // Pointer to the RenderWidgetHostView provided in the last run of
   // |callback_|. This is used to eliminate duplicate callback runs.
   RenderWidgetHostView* last_target_view_;
diff --git a/content/browser/media/capture/web_contents_video_capture_device.cc b/content/browser/media/capture/web_contents_video_capture_device.cc
index a682afa..374a8587 100644
--- a/content/browser/media/capture/web_contents_video_capture_device.cc
+++ b/content/browser/media/capture/web_contents_video_capture_device.cc
@@ -121,10 +121,7 @@
       return nullptr;
     }
 
-    RenderWidgetHostView* view = contents->GetFullscreenRenderWidgetHostView();
-    if (!view) {
-      view = contents->GetRenderWidgetHostView();
-    }
+    RenderWidgetHostView* view = view = contents->GetRenderWidgetHostView();
     // Make sure the RWHV is still associated with a RWH before considering the
     // view "alive." This is because a null RWH indicates the RWHV has had its
     // Destroy() method called.
@@ -145,8 +142,6 @@
                               RenderFrameHost* new_host) final {
     OnPossibleTargetChange();
   }
-  void DidShowFullscreenWidget() final { OnPossibleTargetChange(); }
-  void DidDestroyFullscreenWidget() final { OnPossibleTargetChange(); }
   void WebContentsDestroyed() final {
     Observe(nullptr);
     is_capturing_ = false;
diff --git a/content/browser/renderer_host/DIR_METADATA b/content/browser/renderer_host/DIR_METADATA
new file mode 100644
index 0000000..566b56ab
--- /dev/null
+++ b/content/browser/renderer_host/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals>Core"
+}
+# COMPONENT: Internals>Sandbox>SiteIsolation
+team_email: "site-isolation-dev@chromium.org"
diff --git a/content/browser/renderer_host/OWNERS b/content/browser/renderer_host/OWNERS
index 0abe9e8b..a2db6b9 100644
--- a/content/browser/renderer_host/OWNERS
+++ b/content/browser/renderer_host/OWNERS
@@ -1,6 +1,3 @@
-# COMPONENT: Internals>Core
-# COMPONENT: Internals>Sandbox>SiteIsolation
-# TEAM: site-isolation-dev@chromium.org
 
 # Compositing and input related code.
 kenrb@chromium.org
diff --git a/content/browser/renderer_host/agent_scheduling_group_host.cc b/content/browser/renderer_host/agent_scheduling_group_host.cc
index 337b39f..c12ef12 100644
--- a/content/browser/renderer_host/agent_scheduling_group_host.cc
+++ b/content/browser/renderer_host/agent_scheduling_group_host.cc
@@ -199,10 +199,6 @@
 }
 
 ChannelProxy* AgentSchedulingGroupHost::GetChannel() {
-  // TODO(crbug.com/1111231): If the process is not initialized, it also implies
-  // that it is not Ready, meaning the channel we return here will not be valid.
-  // In that case we should return |nullptr|, but that causes certain tests to
-  // fail. This should be changed once those tests are fixed.
   if (process_.IsInitializedAndNotDead())
     SetUpMojoIfNeeded();
 
@@ -232,11 +228,8 @@
 }
 
 mojom::RouteProvider* AgentSchedulingGroupHost::GetRemoteRouteProvider() {
-  // TODO(domfarolino): Remove `GetRemoteRouteProvider` from `RenderProcessHost`
-  // and make `AgentSchedulingGroupHost` a fully-fledged RouteProvider.
-  RenderProcessHostImpl& process =
-      static_cast<RenderProcessHostImpl&>(process_);
-  return process.GetRemoteRouteProvider(PassKey());
+  SetUpMojoIfNeeded();
+  return remote_route_provider_.get();
 }
 
 void AgentSchedulingGroupHost::CreateFrame(mojom::CreateFrameParamsPtr params) {
@@ -277,34 +270,52 @@
     int32_t routing_id,
     mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterfaceProvider>
         receiver) {
-  // TODO(crbug.com/1111231): Make AgentSchedulingGroupHost a fully-fledged
-  // RouteProvider, so we can register routes directly with an
-  // AgentSchedulingGroupHost rather than RenderProcessHostImpl.
-  static_cast<RenderProcessHostImpl&>(process_).GetRoute(routing_id,
-                                                         std::move(receiver));
+  DCHECK(receiver.is_valid());
+  associated_interface_provider_receivers_.Add(this, std::move(receiver),
+                                               routing_id);
 }
 
 void AgentSchedulingGroupHost::GetAssociatedInterface(
     const std::string& name,
     mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterface>
         receiver) {
-  // TODO(crbug.com/1111231): Make AgentSchedulingGroupHost a fully-fledged
-  // AssociatedInterfaceProvider, so we can start associating interfaces
-  // directly with the AgentSchedulingGroupHost interface.
-  static_cast<RenderProcessHostImpl&>(process_).GetAssociatedInterface(
-      name, std::move(receiver));
+  int32_t routing_id =
+      associated_interface_provider_receivers_.current_context();
+  IPC::Listener* listener =
+      static_cast<RenderProcessHostImpl&>(process_).GetListener(PassKey(),
+                                                                routing_id);
+  if (listener)
+    listener->OnAssociatedInterfaceRequest(name, receiver.PassHandle());
 }
 
 void AgentSchedulingGroupHost::ResetMojo() {
   receiver_.reset();
   mojo_remote_.reset();
+  remote_route_provider_.reset();
+  route_provider_receiver_.reset();
+  associated_interface_provider_receivers_.Clear();
+  // TODO(domfarolino): Move the SetUpMojoIfNeeded() logic to this method, along
+  // with invoking RenderProcessHostImpl::EnableSendQueue(), so that upon
+  // renderer process crash, we immediately reset our mojos.
 }
 
 void AgentSchedulingGroupHost::SetUpMojoIfNeeded() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(process_.IsInitializedAndNotDead());
+  // We don't DCHECK |process_.IsInitializedAndNotDead()| here because we may
+  // end up here after the render process has died but before the
+  // RenderProcessHostImpl is re-initialized (and thus not considered dead
+  // anymore).
 
-  DCHECK_EQ(receiver_.is_bound(), mojo_remote_.is_bound());
+  // The bind states of all of |AgentSchedulingGroupHost|'s remotes and
+  // receivers are expected to be equivalent.
+  DCHECK(process_.GetRendererInterface());
+
+  // Make sure that the bind state of all mojos are equivalent.
+  DCHECK_EQ(mojo_remote_.is_bound(), receiver_.is_bound());
+  DCHECK_EQ(receiver_.is_bound(), remote_route_provider_.is_bound());
+  DCHECK_EQ(remote_route_provider_.is_bound(),
+            route_provider_receiver_.is_bound());
+
   if (receiver_.is_bound())
     return;
 
@@ -317,6 +328,10 @@
         receiver_.BindNewPipeAndPassRemote(),
         mojo_remote_.BindNewPipeAndPassReceiver());
   }
+
+  mojo_remote_.get()->BindAssociatedRouteProvider(
+      route_provider_receiver_.BindNewEndpointAndPassRemote(),
+      remote_route_provider_.BindNewEndpointAndPassReceiver());
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/agent_scheduling_group_host.h b/content/browser/renderer_host/agent_scheduling_group_host.h
index 3a3a2fd..ef475d95 100644
--- a/content/browser/renderer_host/agent_scheduling_group_host.h
+++ b/content/browser/renderer_host/agent_scheduling_group_host.h
@@ -13,6 +13,7 @@
 #include "content/common/renderer.mojom-forward.h"
 #include "content/public/browser/render_process_host_observer.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/associated_receiver_set.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -188,6 +189,20 @@
   // Remote stub of `mojom::AgentSchedulingGroup`, used for sending calls to the
   // (renderer-side) `AgentSchedulingGroup`.
   MaybeAssociatedRemote mojo_remote_;
+
+  // The `mojom::RouteProvider` mojo pair to setup
+  // `blink::AssociatedInterfaceProvider` routes between this and the
+  // renderer-side `AgentSchedulingGroup`.
+  mojo::AssociatedRemote<mojom::RouteProvider> remote_route_provider_;
+  mojo::AssociatedReceiver<mojom::RouteProvider> route_provider_receiver_{this};
+
+  // The `blink::mojom::AssociatedInterfaceProvider` receiver set that *all*
+  // renderer-side `blink::AssociatedInterfaceProvider` objects own a remote to.
+  // `AgentSchedulingGroupHost` will be responsible for routing each associated
+  // interface request to the appropriate renderer host object.
+  mojo::AssociatedReceiverSet<blink::mojom::AssociatedInterfaceProvider,
+                              int32_t>
+      associated_interface_provider_receivers_;
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/input/DIR_METADATA b/content/browser/renderer_host/input/DIR_METADATA
new file mode 100644
index 0000000..b68ea00
--- /dev/null
+++ b/content/browser/renderer_host/input/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>Input"
+}
+
+team_email: "input-dev@chromium.org"
diff --git a/content/browser/renderer_host/input/OWNERS b/content/browser/renderer_host/input/OWNERS
index 41f1fc0a..0afb376 100644
--- a/content/browser/renderer_host/input/OWNERS
+++ b/content/browser/renderer_host/input/OWNERS
@@ -4,12 +4,7 @@
 bokan@chromium.org
 
 
-# TEAM: input-dev@chromium.org
-# COMPONENT: Blink>Input
 dtapuska@chromium.org
 tdresser@chromium.org
 bokan@chromium.org
 
-
-# TEAM: input-dev@chromium.org
-# COMPONENT: Blink>Input
diff --git a/content/browser/renderer_host/media/DIR_METADATA b/content/browser/renderer_host/media/DIR_METADATA
new file mode 100644
index 0000000..066f18a
--- /dev/null
+++ b/content/browser/renderer_host/media/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>GetUserMedia"
+}
+
+team_email: "webrtc-dev@chromium.org"
diff --git a/content/browser/renderer_host/media/OWNERS b/content/browser/renderer_host/media/OWNERS
index 0cd4b45..2113780 100644
--- a/content/browser/renderer_host/media/OWNERS
+++ b/content/browser/renderer_host/media/OWNERS
@@ -9,6 +9,3 @@
 per-file *video*=chfremer@chromium.org
 per-file *video*=emircan@chromium.org
 per-file *video*=mcasas@chromium.org
-
-# TEAM: webrtc-dev@chromium.org
-# COMPONENT: Blink>GetUserMedia
diff --git a/content/browser/renderer_host/p2p/DIR_METADATA b/content/browser/renderer_host/p2p/DIR_METADATA
new file mode 100644
index 0000000..66cc019
--- /dev/null
+++ b/content/browser/renderer_host/p2p/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>WebRTC"
+}
diff --git a/content/browser/renderer_host/p2p/OWNERS b/content/browser/renderer_host/p2p/OWNERS
index eabc2b2..f73d253 100644
--- a/content/browser/renderer_host/p2p/OWNERS
+++ b/content/browser/renderer_host/p2p/OWNERS
@@ -1,5 +1,3 @@
 guidou@chromium.org
 sergeyu@chromium.org
 steveanton@chromium.org
-
-# COMPONENT: Blink>WebRTC
diff --git a/content/browser/renderer_host/pepper/DIR_METADATA b/content/browser/renderer_host/pepper/DIR_METADATA
new file mode 100644
index 0000000..03adff3
--- /dev/null
+++ b/content/browser/renderer_host/pepper/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Plugins>Pepper"
+}
diff --git a/content/browser/renderer_host/pepper/OWNERS b/content/browser/renderer_host/pepper/OWNERS
index c1e2e404..f129781 100644
--- a/content/browser/renderer_host/pepper/OWNERS
+++ b/content/browser/renderer_host/pepper/OWNERS
@@ -1,4 +1,2 @@
 bbudge@chromium.org
 raymes@chromium.org
-
-# COMPONENT: Internals>Plugins>Pepper
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 6c1bfb9..b596fff0 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1947,8 +1947,6 @@
   //
   // See OnProcessLaunched() for some additional details of this somewhat
   // surprising behavior.
-  remote_route_provider_.reset();
-  channel_->GetRemoteAssociatedInterface(&remote_route_provider_);
   renderer_interface_.reset();
   channel_->GetRemoteAssociatedInterface(&renderer_interface_);
 
@@ -2483,8 +2481,6 @@
   // This base::Unretained() usage is safe since the associated_registry is
   // owned by this RPHI.
   associated_registry->AddInterface(base::BindRepeating(
-      &RenderProcessHostImpl::BindRouteProvider, base::Unretained(this)));
-  associated_registry->AddInterface(base::BindRepeating(
       &RenderProcessHostImpl::CreateRendererHost, base::Unretained(this)));
 
   AddUIThreadInterface(
@@ -2537,31 +2533,10 @@
       std::move(registry), std::move(child_host_pending_receiver_));
 }
 
-void RenderProcessHostImpl::BindRouteProvider(
-    mojo::PendingAssociatedReceiver<mojom::RouteProvider> receiver) {
-  if (route_provider_receiver_.is_bound())
-    return;
-  route_provider_receiver_.Bind(std::move(receiver));
-}
-
-void RenderProcessHostImpl::GetRoute(
-    int32_t routing_id,
-    mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterfaceProvider>
-        receiver) {
-  DCHECK(receiver.is_valid());
-  associated_interface_provider_receivers_.Add(this, std::move(receiver),
-                                               routing_id);
-}
-
-void RenderProcessHostImpl::GetAssociatedInterface(
-    const std::string& name,
-    mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterface>
-        receiver) {
-  int32_t routing_id =
-      associated_interface_provider_receivers_.current_context();
-  IPC::Listener* listener = listeners_.Lookup(routing_id);
-  if (listener)
-    listener->OnAssociatedInterfaceRequest(name, receiver.PassHandle());
+IPC::Listener* RenderProcessHostImpl::GetListener(
+    util::PassKey<AgentSchedulingGroupHost>,
+    int32_t routing_id) {
+  return listeners_.Lookup(routing_id);
 }
 
 void RenderProcessHostImpl::CreateEmbeddedFrameSinkProvider(
@@ -2856,11 +2831,6 @@
   is_unused_ = false;
 }
 
-mojom::RouteProvider* RenderProcessHostImpl::GetRemoteRouteProvider(
-    util::PassKey<AgentSchedulingGroupHost>) {
-  return remote_route_provider_.get();
-}
-
 void RenderProcessHostImpl::AddRoute(int32_t routing_id,
                                      IPC::Listener* listener) {
   TRACE_EVENT2("shutdown", "RenderProcessHostImpl::AddRoute",
@@ -4634,8 +4604,6 @@
 void RenderProcessHostImpl::ResetIPC() {
   renderer_host_receiver_.reset();
   io_thread_host_impl_.reset();
-  route_provider_receiver_.reset();
-  associated_interface_provider_receivers_.Clear();
   associated_interfaces_.reset();
   coordinator_connector_receiver_.reset();
   tracing_registration_.reset();
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 52ac9a3..8fa93de3 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -29,6 +29,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/sequence_bound.h"
+#include "base/util/type_safety/pass_key.h"
 #include "build/build_config.h"
 #include "content/browser/child_process_launcher.h"
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
@@ -159,8 +160,6 @@
 class CONTENT_EXPORT RenderProcessHostImpl
     : public RenderProcessHost,
       public ChildProcessLauncher::Client,
-      public mojom::RouteProvider,
-      public blink::mojom::AssociatedInterfaceProvider,
       public mojom::RendererHost,
       public blink::mojom::DomStorageProvider,
       public memory_instrumentation::mojom::CoordinatorConnector {
@@ -273,9 +272,6 @@
   void DumpProfilingData(base::OnceClosure callback) override;
 #endif
 
-  mojom::RouteProvider* GetRemoteRouteProvider(
-      util::PassKey<AgentSchedulingGroupHost>);
-
   // IPC::Sender via RenderProcessHost.
   bool Send(IPC::Message* msg) override;
 
@@ -747,17 +743,11 @@
   // Registers Mojo interfaces to be exposed to the renderer.
   void RegisterMojoInterfaces();
 
-  // mojom::RouteProvider:
-  void GetRoute(
-      int32_t routing_id,
-      mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterfaceProvider>
-          receiver) override;
-
-  // blink::mojom::AssociatedInterfaceProvider:
-  void GetAssociatedInterface(
-      const std::string& name,
-      mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterface>
-          receiver) override;
+  // TODO(crbug.com/1132901): We'll be able to remove this method once
+  // `AgentSchedulingGroupHost` maintains its own map of IPC::Listeners, but for
+  // now we'll let it delegate to this class.
+  IPC::Listener* GetListener(util::PassKey<AgentSchedulingGroupHost>,
+                             int32_t routing_id);
 
   // mojom::RendererHost
   using BrowserHistogramCallback =
@@ -770,9 +760,6 @@
       const GURL& url,
       mojom::RendererHost::ResolveProxyCallback callback) override;
 
-  void BindRouteProvider(
-      mojo::PendingAssociatedReceiver<mojom::RouteProvider> receiver);
-
   void CreateEmbeddedFrameSinkProvider(
       mojo::PendingReceiver<blink::mojom::EmbeddedFrameSinkProvider> receiver);
   void BindCompositingModeReporter(
@@ -986,11 +973,6 @@
   // nature (e.g. metrics, memory usage).
   std::unique_ptr<blink::AssociatedInterfaceRegistry> associated_interfaces_;
 
-  mojo::AssociatedReceiver<mojom::RouteProvider> route_provider_receiver_{this};
-  mojo::AssociatedReceiverSet<blink::mojom::AssociatedInterfaceProvider,
-                              int32_t>
-      associated_interface_provider_receivers_;
-
   // These fields are cached values that are updated in
   // UpdateProcessPriorityInputs, and are used to compute priority sent to
   // ChildProcessLauncher.
@@ -1169,7 +1151,6 @@
   mojo::Remote<mojom::ChildProcess> child_process_;
   // This will be bound to |io_thread_host_impl_|.
   mojo::PendingReceiver<mojom::ChildProcessHost> child_host_pending_receiver_;
-  mojo::AssociatedRemote<mojom::RouteProvider> remote_route_provider_;
   mojo::AssociatedRemote<mojom::Renderer> renderer_interface_;
   mojo::AssociatedReceiver<mojom::RendererHost> renderer_host_receiver_{this};
   mojo::Receiver<memory_instrumentation::mojom::CoordinatorConnector>
diff --git a/content/browser/renderer_host/render_widget_host_delegate.cc b/content/browser/renderer_host/render_widget_host_delegate.cc
index 66650c6..8f98ef9 100644
--- a/content/browser/renderer_host/render_widget_host_delegate.cc
+++ b/content/browser/renderer_host/render_widget_host_delegate.cc
@@ -122,11 +122,6 @@
   return nullptr;
 }
 
-RenderWidgetHostImpl* RenderWidgetHostDelegate::GetFullscreenRenderWidgetHost()
-    const {
-  return nullptr;
-}
-
 bool RenderWidgetHostDelegate::OnUpdateDragCursor() {
   return false;
 }
diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h
index c44d658..cbe1b66e 100644
--- a/content/browser/renderer_host/render_widget_host_delegate.h
+++ b/content/browser/renderer_host/render_widget_host_delegate.h
@@ -70,19 +70,12 @@
   // The RenderWidgetHost is going to be deleted.
   virtual void RenderWidgetDeleted(RenderWidgetHostImpl* render_widget_host) {}
 
-  // The RenderWidgetHost got the focus.
-  virtual void RenderWidgetGotFocus(RenderWidgetHostImpl* render_widget_host) {}
-
   // If a main frame navigation is in progress, this will return the zoom level
   // for the pending page. Otherwise, this returns the zoom level for the
   // current page. Note that subframe navigations do not affect the zoom level,
   // which is tracked at the level of the page.
   virtual double GetPendingPageZoomLevel();
 
-  // The RenderWidgetHost lost the focus.
-  virtual void RenderWidgetLostFocus(
-      RenderWidgetHostImpl* render_widget_host) {}
-
   // The RenderWidget was resized.
   virtual void RenderWidgetWasResized(RenderWidgetHostImpl* render_widget_host,
                                       bool width_changed) {}
@@ -272,11 +265,6 @@
   // Returns the associated RenderViewHostDelegateView*, if possible.
   virtual RenderViewHostDelegateView* GetDelegateView();
 
-  // Returns the current Flash fullscreen RenderWidgetHostImpl if any. This is
-  // not intended for use with other types of fullscreen, such as HTML
-  // fullscreen, and will return nullptr for those cases.
-  virtual RenderWidgetHostImpl* GetFullscreenRenderWidgetHost() const;
-
   // Allow the delegate to handle the cursor update. Returns true if handled.
   virtual bool OnUpdateDragCursor();
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 36ea933..2edfd99 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1122,16 +1122,12 @@
   Focus();
   if (owner_delegate_)
     owner_delegate_->RenderWidgetGotFocus();
-  if (delegate_)
-    delegate_->RenderWidgetGotFocus(this);
 }
 
 void RenderWidgetHostImpl::LostFocus() {
   Blur();
   if (owner_delegate_)
     owner_delegate_->RenderWidgetLostFocus();
-  if (delegate_)
-    delegate_->RenderWidgetLostFocus(this);
 }
 
 void RenderWidgetHostImpl::Focus() {
diff --git a/content/browser/renderer_host/text_input_client_mac.mm b/content/browser/renderer_host/text_input_client_mac.mm
index 452df558..a65061f 100644
--- a/content/browser/renderer_host/text_input_client_mac.mm
+++ b/content/browser/renderer_host/text_input_client_mac.mm
@@ -21,20 +21,6 @@
 
 namespace {
 
-// TODO(ekaramad): TextInputClientMac expects to have a RenderWidgetHost to use
-// for handling mojo calls. However, for fullscreen flash, we end up with a
-// PepperWidget. For those scenarios, do not send the mojo calls. We need to
-// figure out what features are properly supported and perhaps send the
-// mojo call to the parent widget of the plugin (https://crbug.com/663384).
-bool IsFullScreenRenderWidget(RenderWidgetHost* widget) {
-  RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(widget);
-  if (!rwhi->delegate() ||
-      rwhi == rwhi->delegate()->GetFullscreenRenderWidgetHost()) {
-    return true;
-  }
-  return false;
-}
-
 RenderFrameHostImpl* GetFocusedRenderFrameHostImpl(RenderWidgetHost* widget) {
   RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(widget);
   FrameTree* tree = rwhi->delegate()->GetFrameTree();
@@ -88,9 +74,6 @@
 
 uint32_t TextInputClientMac::GetCharacterIndexAtPoint(RenderWidgetHost* rwh,
                                                       const gfx::Point& point) {
-  if (IsFullScreenRenderWidget(rwh))
-    return UINT32_MAX;
-
   RenderFrameHostImpl* rfhi = GetFocusedRenderFrameHostImpl(rwh);
   // If it doesn't have a focused frame, it calls
   // SetCharacterIndexAndSignal() with index 0.
@@ -117,9 +100,6 @@
 
 gfx::Rect TextInputClientMac::GetFirstRectForRange(RenderWidgetHost* rwh,
                                                    const gfx::Range& range) {
-  if (IsFullScreenRenderWidget(rwh))
-    return gfx::Rect();
-
   RenderFrameHostImpl* rfhi = GetFocusedRenderFrameHostImpl(rwh);
   if (!rfhi)
     return gfx::Rect();
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 98875af..23d44183 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -820,9 +820,6 @@
       maximum_zoom_percent_(
           static_cast<int>(blink::kMaximumPageZoomFactor * 100)),
       zoom_scroll_remainder_(0),
-      fullscreen_widget_process_id_(ChildProcessHost::kInvalidUniqueID),
-      fullscreen_widget_routing_id_(MSG_ROUTING_NONE),
-      fullscreen_widget_had_focus_at_shutdown_(false),
       force_disable_overscroll_content_(false),
       last_dialog_suppressed_(false),
       accessibility_mode_(
@@ -1336,12 +1333,6 @@
   return GetRenderManager()->GetRenderWidgetHostView();
 }
 
-RenderWidgetHostView* WebContentsImpl::GetFullscreenRenderWidgetHostView() {
-  if (auto* widget_host = GetFullscreenRenderWidgetHost())
-    return widget_host->GetView();
-  return nullptr;
-}
-
 WebContentsView* WebContentsImpl::GetView() const {
   return view_.get();
 }
@@ -2703,21 +2694,11 @@
   switch (type) {
     case NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
       RenderWidgetHost* host = Source<RenderWidgetHost>(source).ptr();
-      RenderWidgetHostView* view = host->GetView();
-      if (view == GetFullscreenRenderWidgetHostView()) {
-        // We cannot just call view_->RestoreFocus() here.  On some platforms,
-        // attempting to focus the currently-invisible WebContentsView will be
-        // flat-out ignored.  Therefore, this boolean is used to track whether
-        // we will request focus after the fullscreen widget has been
-        // destroyed.
-        fullscreen_widget_had_focus_at_shutdown_ = (view && view->HasFocus());
-      } else {
-        for (auto i = pending_widget_views_.begin();
-             i != pending_widget_views_.end(); ++i) {
-          if (host->GetView() == i->second) {
-            pending_widget_views_.erase(i);
-            break;
-          }
+      for (auto i = pending_widget_views_.begin();
+           i != pending_widget_views_.end(); ++i) {
+        if (host->GetView() == i->second) {
+          pending_widget_views_.erase(i);
+          break;
         }
       }
       break;
@@ -2975,49 +2956,12 @@
   if (is_being_destroyed_)
     return;
 
-  if (render_widget_host &&
-      render_widget_host->GetRoutingID() == fullscreen_widget_routing_id_ &&
-      render_widget_host->GetProcess()->GetID() ==
-          fullscreen_widget_process_id_) {
-    if (delegate_ && delegate_->EmbedsFullscreenWidget())
-      delegate_->ExitFullscreenModeForTab(this);
-    observers_.ForEachObserver([&](WebContentsObserver* observer) {
-      observer->DidDestroyFullscreenWidget();
-    });
-    fullscreen_widget_process_id_ = ChildProcessHost::kInvalidUniqueID;
-    fullscreen_widget_routing_id_ = MSG_ROUTING_NONE;
-    if (fullscreen_widget_had_focus_at_shutdown_)
-      view_->RestoreFocus();
-  }
-
   if (render_widget_host == mouse_lock_widget_)
     LostMouseLock(mouse_lock_widget_);
 
   CancelKeyboardLock(render_widget_host);
 }
 
-void WebContentsImpl::RenderWidgetGotFocus(
-    RenderWidgetHostImpl* render_widget_host) {
-  OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::RenderWidgetGotFocus",
-                        "render_widget_host", render_widget_host);
-  // Notify the observers if an embedded fullscreen widget was focused.
-  if (delegate_ && render_widget_host && delegate_->EmbedsFullscreenWidget() &&
-      render_widget_host->GetView() == GetFullscreenRenderWidgetHostView()) {
-    NotifyWebContentsFocused(render_widget_host);
-  }
-}
-
-void WebContentsImpl::RenderWidgetLostFocus(
-    RenderWidgetHostImpl* render_widget_host) {
-  OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::RenderWidgetLostFocus",
-                        "render_widget_host", render_widget_host);
-  // Notify the observers if an embedded fullscreen widget lost focus.
-  if (delegate_ && render_widget_host && delegate_->EmbedsFullscreenWidget() &&
-      render_widget_host->GetView() == GetFullscreenRenderWidgetHostView()) {
-    NotifyWebContentsLostFocus(render_widget_host);
-  }
-}
-
 void WebContentsImpl::RenderWidgetWasResized(
     RenderWidgetHostImpl* render_widget_host,
     bool width_changed) {
@@ -3189,14 +3133,6 @@
   OPTIONAL_TRACE_EVENT0("content", "WebContentsImpl::EnterFullscreenMode");
   DCHECK(CanEnterFullscreenMode());
 
-  // This method is being called to enter renderer-initiated fullscreen mode.
-  // Make sure any existing fullscreen widget is shut down first.
-  RenderWidgetHostView* const widget_view = GetFullscreenRenderWidgetHostView();
-  if (widget_view) {
-    RenderWidgetHostImpl::From(widget_view->GetRenderWidgetHost())
-        ->ShutdownAndDestroyWidget(true);
-  }
-
   if (delegate_) {
     delegate_->EnterFullscreenModeForTab(requesting_frame, options);
 
@@ -3213,14 +3149,6 @@
 void WebContentsImpl::ExitFullscreenMode(bool will_cause_resize) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::ExitFullscreenMode",
                         "will_cause_resize", will_cause_resize);
-  // This method is being called to leave renderer-initiated fullscreen mode.
-  // Make sure any existing fullscreen widget is shut down first.
-  RenderWidgetHostView* const widget_view = GetFullscreenRenderWidgetHostView();
-  if (widget_view) {
-    RenderWidgetHostImpl::From(widget_view->GetRenderWidgetHost())
-        ->ShutdownAndDestroyWidget(true);
-  }
-
   if (delegate_) {
     delegate_->ExitFullscreenModeForTab(this);
 
@@ -3500,9 +3428,7 @@
 
 RenderWidgetHostImpl* WebContentsImpl::GetMouseLockWidget() {
   auto* widget_host = GetTopLevelRenderWidgetHostView();
-  if ((widget_host && widget_host->IsMouseLocked()) ||
-      (GetFullscreenRenderWidgetHostView() &&
-       GetFullscreenRenderWidgetHostView()->IsMouseLocked())) {
+  if (widget_host && widget_host->IsMouseLocked()) {
     return mouse_lock_widget_;
   }
 
@@ -7391,15 +7317,6 @@
                         "render_frame_host",
                         base::trace_event::ToTracedValue(render_frame_host),
                         "url", base::trace_event::ValueToString(url));
-  if (fullscreen_widget_routing_id_ != MSG_ROUTING_NONE) {
-    // If we're in flash fullscreen (i.e. Pepper plugin fullscreen) only update
-    // the url if it's from the fullscreen renderer.
-    RenderWidgetHostView* fs = GetFullscreenRenderWidgetHostView();
-    RenderViewHost* render_view_host = render_frame_host->GetRenderViewHost();
-    if (fs && fs->GetRenderWidgetHost() != render_view_host->GetWidget())
-      return;
-  }
-
   // In case of racey updates from multiple RenderViewHosts, the last URL should
   // be shown - see also some discussion in https://crbug.com/807776.
   if (!url.is_valid() && render_frame_host != frame_that_set_last_target_url_)
@@ -8010,11 +7927,6 @@
   return node_.outer_contents_frame_tree_node_id();
 }
 
-RenderWidgetHostImpl* WebContentsImpl::GetFullscreenRenderWidgetHost() const {
-  return RenderWidgetHostImpl::FromID(fullscreen_widget_process_id_,
-                                      fullscreen_widget_routing_id_);
-}
-
 RenderFrameHostManager* WebContentsImpl::GetRenderManager() const {
   return frame_tree_.root()->render_manager();
 }
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 7bb80ab..1d602b6 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -348,7 +348,6 @@
   RenderWidgetHostView* GetRenderWidgetHostView() override;
   RenderWidgetHostView* GetTopLevelRenderWidgetHostView() override;
   void ClosePage() override;
-  RenderWidgetHostView* GetFullscreenRenderWidgetHostView() override;
   base::Optional<SkColor> GetThemeColor() override;
   base::Optional<SkColor> GetBackgroundColor() override;
   WebUI* GetWebUI() override;
@@ -871,8 +870,6 @@
   void SetTopControlsGestureScrollInProgress(bool in_progress) override;
   void RenderWidgetCreated(RenderWidgetHostImpl* render_widget_host) override;
   void RenderWidgetDeleted(RenderWidgetHostImpl* render_widget_host) override;
-  void RenderWidgetGotFocus(RenderWidgetHostImpl* render_widget_host) override;
-  void RenderWidgetLostFocus(RenderWidgetHostImpl* render_widget_host) override;
   void RenderWidgetWasResized(RenderWidgetHostImpl* render_widget_host,
                               bool width_changed) override;
   void ResizeDueToAutoResize(RenderWidgetHostImpl* render_widget_host,
@@ -973,7 +970,6 @@
   bool FocusLocationBarByDefault() override;
   bool IsHidden() override;
   int GetOuterDelegateFrameTreeNodeId() override;
-  RenderWidgetHostImpl* GetFullscreenRenderWidgetHost() const override;
 
   // blink::mojom::ColorChooserFactory ---------------------------------------
 
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc
index 1d4ca194..9871651 100644
--- a/content/browser/web_contents/web_contents_view_android.cc
+++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -178,12 +178,6 @@
 }
 
 void WebContentsViewAndroid::FocusThroughTabTraversal(bool reverse) {
-  content::RenderWidgetHostView* fullscreen_view =
-      web_contents_->GetFullscreenRenderWidgetHostView();
-  if (fullscreen_view) {
-    fullscreen_view->Focus();
-    return;
-  }
   web_contents_->GetRenderViewHost()->SetInitialFocus(reverse);
 }
 
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc
index 5d4dac32..88e0a39 100644
--- a/content/browser/web_contents/web_contents_view_aura.cc
+++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -819,10 +819,7 @@
   if (delegate_ && delegate_->Focus())
     return;
 
-  RenderWidgetHostView* rwhv =
-      web_contents_->GetFullscreenRenderWidgetHostView();
-  if (!rwhv)
-    rwhv = web_contents_->GetRenderWidgetHostView();
+  RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView();
   if (rwhv)
     rwhv->Focus();
 }
@@ -852,12 +849,6 @@
   if (delegate_)
     delegate_->ResetStoredFocus();
 
-  content::RenderWidgetHostView* fullscreen_view =
-      web_contents_->GetFullscreenRenderWidgetHostView();
-  if (fullscreen_view) {
-    fullscreen_view->Focus();
-    return;
-  }
   web_contents_->GetRenderViewHost()->SetInitialFocus(reverse);
 }
 
diff --git a/content/browser/web_contents/web_contents_view_mac.mm b/content/browser/web_contents/web_contents_view_mac.mm
index c5521a2..8a42e293 100644
--- a/content/browser/web_contents/web_contents_view_mac.mm
+++ b/content/browser/web_contents/web_contents_view_mac.mm
@@ -174,10 +174,7 @@
   // Focus the the fullscreen view, if one exists; otherwise, focus the content
   // native view. This ensures that the view currently attached to a NSWindow is
   // being used to query or set first responder state.
-  RenderWidgetHostView* rwhv =
-      web_contents_->GetFullscreenRenderWidgetHostView();
-  if (!rwhv)
-    rwhv = web_contents_->GetRenderWidgetHostView();
+  RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView();
   if (!rwhv)
     return;
 
@@ -215,12 +212,6 @@
   if (delegate())
     delegate()->ResetStoredFocus();
 
-  content::RenderWidgetHostView* fullscreen_view =
-      web_contents_->GetFullscreenRenderWidgetHostView();
-  if (fullscreen_view) {
-    fullscreen_view->Focus();
-    return;
-  }
   web_contents_->GetRenderViewHost()->SetInitialFocus(reverse);
 }
 
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index 2a5eaf6..fac5956 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -843,14 +843,8 @@
   return static_cast<bool>(browser_process_io_runner_);
 }
 
-void ChildThreadImpl::GetAssociatedInterface(
-    int32_t routing_id,
-    const std::string& name,
-    mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterface>
-        receiver) {
-  Listener* route = router_.GetRoute(routing_id);
-  if (route)
-    route->OnAssociatedInterfaceRequest(name, receiver.PassHandle());
+IPC::Listener* ChildThreadImpl::GetListener(int32_t routing_id) {
+  return router_.GetRoute(routing_id);
 }
 
 }  // namespace content
diff --git a/content/child/child_thread_impl.h b/content/child/child_thread_impl.h
index bd07f46..664efd0 100644
--- a/content/child/child_thread_impl.h
+++ b/content/child/child_thread_impl.h
@@ -161,11 +161,10 @@
 
   bool IsInBrowserProcess() const;
 
-  void GetAssociatedInterface(
-      int32_t routing_id,
-      const std::string& name,
-      mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterface>
-          receiver);
+  // TODO(1132901) We'll be able to move this method once |AgentSchedulingGroup|
+  // maintains its own map of IPC::Listeners, but for now we'll let it delegate
+  // to this class.
+  virtual IPC::Listener* GetListener(int32_t routing_id);
 
  private:
   // TODO(crbug.com/1111231): This class is a friend so that it can call our
diff --git a/content/common/agent_scheduling_group.mojom b/content/common/agent_scheduling_group.mojom
index 132ea76f..da2309b 100644
--- a/content/common/agent_scheduling_group.mojom
+++ b/content/common/agent_scheduling_group.mojom
@@ -4,6 +4,7 @@
 
 module content.mojom;
 
+import "content/common/associated_interfaces.mojom";
 import "content/common/document_scoped_interface_bundle.mojom";
 import "content/common/native_types.mojom";
 import "ipc/constants.mojom";
@@ -206,6 +207,21 @@
 // AgentSchedulingGroupHost and the renderer process's AgentSchedulingGroup.
 // Implemented by content::AgentSchedulingGroup (in the renderer process).
 interface AgentSchedulingGroup {
+  // Tells the renderer to bind the receiver to a backing RouteProvider
+  // implementation, which in practice is itself. Also passes a remote to the
+  // RouteProvider interface owned by AgentSchedulingGroupHost so that we
+  // immediately have bidirectional RouteProvider communication between
+  // AgentSchedulingGroup <=> AgentSchedulingGroupHost. We have this as a
+  // method on this interface, as opposed to passing this remote/receiver pair
+  // over the method that creates the remote AgentSchedulingGroup. This is
+  // because we need the RouteProvider remote/receiver pair to be associated
+  // with the message pipe that the AgentSchedulingGroup is associated with,
+  // which may be different than the message pipe that we create the
+  // AgentSchedulingGroup over.
+  BindAssociatedRouteProvider(
+    pending_associated_remote<RouteProvider> remote,
+    pending_associated_receiver<RouteProvider> receiver);
+
   // Tells the renderer to create a new view.
   CreateView(CreateViewParams params);
 
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 9da82cb4..7c95dd0 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -382,10 +382,6 @@
   // handler.
   virtual void ClosePage() = 0;
 
-  // Returns the currently active fullscreen widget. If there is none, returns
-  // nullptr.
-  virtual RenderWidgetHostView* GetFullscreenRenderWidgetHostView() = 0;
-
   // Returns the theme color for the underlying content as set by the
   // theme-color meta tag if any.
   virtual base::Optional<SkColor> GetThemeColor() = 0;
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index 12ce6646..331be91 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -165,10 +165,6 @@
   return nullptr;
 }
 
-bool WebContentsDelegate::EmbedsFullscreenWidget() {
-  return false;
-}
-
 bool WebContentsDelegate::IsFullscreenForTabOrPending(
     const WebContents* web_contents) {
   return false;
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index ee6b87d4..5f8ccea 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -448,12 +448,6 @@
       RenderFrameHost* frame,
       const BluetoothScanningPrompt::EventHandler& event_handler);
 
-  // Returns true if the delegate will embed a WebContents-owned fullscreen
-  // render widget.  In this case, the delegate may access the widget by calling
-  // WebContents::GetFullscreenRenderWidgetHostView().  If false is returned,
-  // WebContents will be responsible for showing the fullscreen widget.
-  virtual bool EmbedsFullscreenWidget();
-
   // Called when the renderer puts a tab into fullscreen mode.
   // |requesting_frame| is the specific content frame requesting fullscreen.
   virtual void EnterFullscreenModeForTab(
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h
index 41c4e51..864b2ba 100644
--- a/content/public/browser/web_contents_observer.h
+++ b/content/public/browser/web_contents_observer.h
@@ -482,11 +482,6 @@
   // Invoked when the WebContents is muted/unmuted.
   virtual void DidUpdateAudioMutingState(bool muted) {}
 
-  // Invoked when a pepper plugin creates and shows or destroys a fullscreen
-  // RenderWidget.
-  virtual void DidShowFullscreenWidget() {}
-  virtual void DidDestroyFullscreenWidget() {}
-
   // Invoked when the renderer process has toggled the tab into/out of
   // fullscreen mode.
   virtual void DidToggleFullscreenModeForTab(bool entered_fullscreen,
diff --git a/content/public/renderer/render_thread.h b/content/public/renderer/render_thread.h
index 4f0fbe6..7803947 100644
--- a/content/public/renderer/render_thread.h
+++ b/content/public/renderer/render_thread.h
@@ -12,7 +12,6 @@
 #include "base/callback.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/single_thread_task_runner.h"
-#include "base/util/type_safety/pass_key.h"
 #include "content/common/content_export.h"
 #include "content/public/child/child_thread.h"
 #include "ipc/ipc_channel_proxy.h"
@@ -43,12 +42,6 @@
 }  // namespace v8
 
 namespace content {
-class AgentSchedulingGroup;
-
-namespace mojom {
-class RouteProvider;
-}  // namespace mojom
-
 class RenderThreadObserver;
 class ResourceDispatcherDelegate;
 
@@ -82,9 +75,6 @@
   virtual void AddObserver(RenderThreadObserver* observer) = 0;
   virtual void RemoveObserver(RenderThreadObserver* observer) = 0;
 
-  virtual mojom::RouteProvider* GetRemoteRouteProvider(
-      util::PassKey<AgentSchedulingGroup>) = 0;
-
   // Set the ResourceDispatcher delegate object for this process.
   virtual void SetResourceDispatcherDelegate(
       ResourceDispatcherDelegate* delegate) = 0;
diff --git a/content/public/test/mock_render_thread.cc b/content/public/test/mock_render_thread.cc
index 6d3ebe8..f4f66903c 100644
--- a/content/public/test/mock_render_thread.cc
+++ b/content/public/test/mock_render_thread.cc
@@ -58,18 +58,6 @@
 #endif
 };
 
-// Some tests require that a valid mojo::RouteProvider* be accessed to send
-// messages over. The RouteProvider does not need to be bound to any real
-// implementation, so we simply bind it to a pipe that we'll forget about, as to
-// drain all messages sent over the remote.
-mojom::RouteProvider* GetStaticRemoteRouteProvider() {
-  static mojo::Remote<mojom::RouteProvider> remote;
-  if (!remote) {
-    ignore_result(remote.BindNewPipeAndPassReceiver());
-  }
-  return remote.get();
-}
-
 }  // namespace
 
 MockRenderThread::MockRenderThread()
@@ -171,11 +159,6 @@
   observers_.RemoveObserver(observer);
 }
 
-mojom::RouteProvider* MockRenderThread::GetRemoteRouteProvider(
-    util::PassKey<AgentSchedulingGroup>) {
-  return GetStaticRemoteRouteProvider();
-}
-
 void MockRenderThread::SetResourceDispatcherDelegate(
     ResourceDispatcherDelegate* delegate) {
 }
diff --git a/content/public/test/mock_render_thread.h b/content/public/test/mock_render_thread.h
index 822d051..110c379 100644
--- a/content/public/test/mock_render_thread.h
+++ b/content/public/test/mock_render_thread.h
@@ -11,7 +11,6 @@
 #include "base/observer_list.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string16.h"
-#include "base/util/type_safety/pass_key.h"
 #include "build/build_config.h"
 #include "content/public/common/widget_type.h"
 #include "content/public/renderer/render_thread.h"
@@ -41,7 +40,6 @@
 class CreateNewWindowParams;
 class CreateNewWindowReply;
 class RenderMessageFilter;
-class RouteProvider;
 }
 
 // This class is a very simple mock of RenderThread. It simulates an IPC channel
@@ -70,8 +68,6 @@
   void RemoveFilter(IPC::MessageFilter* filter) override;
   void AddObserver(RenderThreadObserver* observer) override;
   void RemoveObserver(RenderThreadObserver* observer) override;
-  mojom::RouteProvider* GetRemoteRouteProvider(
-      util::PassKey<AgentSchedulingGroup>) override;
   void SetResourceDispatcherDelegate(
       ResourceDispatcherDelegate* delegate) override;
   void RecordAction(const base::UserMetricsAction& action) override;
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index 91bf3e5..02f113f58 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -29,8 +29,8 @@
 #include "content/public/renderer/render_view_visitor.h"
 #include "content/public/test/fake_render_widget_host.h"
 #include "content/public/test/frame_load_waiter.h"
-#include "content/renderer/agent_scheduling_group.h"
 #include "content/renderer/loader/resource_dispatcher.h"
+#include "content/renderer/mock_agent_scheduling_group.h"
 #include "content/renderer/render_process.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/render_view_impl.h"
@@ -226,15 +226,17 @@
 
 std::unique_ptr<AgentSchedulingGroup> CreateAgentSchedulingGroup(
     RenderThread& render_thread) {
+  // Fake mojos for the AgentSchedulingGroupHost interface.
   mojo::PendingAssociatedRemote<mojom::AgentSchedulingGroupHost>
       agent_scheduling_group_host;
   ignore_result(
       agent_scheduling_group_host.InitWithNewEndpointAndPassReceiver());
   mojo::PendingAssociatedReceiver<mojom::AgentSchedulingGroup>
-      agent_scheduling_group_mojo;
-  return std::make_unique<AgentSchedulingGroup>(
+      agent_scheduling_group_receiver;
+
+  return std::make_unique<MockAgentSchedulingGroup>(
       render_thread, std::move(agent_scheduling_group_host),
-      std::move(agent_scheduling_group_mojo),
+      std::move(agent_scheduling_group_receiver),
       base::OnceCallback<void(const AgentSchedulingGroup*)>());
 }
 
diff --git a/content/renderer/agent_scheduling_group.cc b/content/renderer/agent_scheduling_group.cc
index 0b54d6d..e0dd2a3e 100644
--- a/content/renderer/agent_scheduling_group.cc
+++ b/content/renderer/agent_scheduling_group.cc
@@ -74,6 +74,11 @@
 
 AgentSchedulingGroup::MaybeAssociatedRemote::~MaybeAssociatedRemote() = default;
 
+mojom::AgentSchedulingGroupHost*
+AgentSchedulingGroup::MaybeAssociatedRemote::get() {
+  return absl::visit([](auto& r) { return r.get(); }, remote_);
+}
+
 // AgentSchedulingGroup:
 AgentSchedulingGroup::AgentSchedulingGroup(
     RenderThread& render_thread,
@@ -140,7 +145,8 @@
 }
 
 mojom::RouteProvider* AgentSchedulingGroup::GetRemoteRouteProvider() {
-  return render_thread_.GetRemoteRouteProvider(PassKey());
+  DCHECK(remote_route_provider_);
+  return remote_route_provider_.get();
 }
 
 void AgentSchedulingGroup::CreateView(mojom::CreateViewParamsPtr params) {
@@ -170,24 +176,34 @@
                         devtools_frame_token, PassKey());
 }
 
+void AgentSchedulingGroup::BindAssociatedRouteProvider(
+    mojo::PendingAssociatedRemote<mojom::RouteProvider> remote,
+    mojo::PendingAssociatedReceiver<mojom::RouteProvider> receiver) {
+  remote_route_provider_.Bind(std::move(remote));
+  route_provider_receiver_.Bind(std::move(receiver),
+                                ToImpl(render_thread_)
+                                    .GetWebMainThreadScheduler()
+                                    ->DeprecatedDefaultTaskRunner());
+}
+
 void AgentSchedulingGroup::GetRoute(
     int32_t routing_id,
     mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterfaceProvider>
         receiver) {
-  // TODO(crbug.com/1111231): Make AgentSchedulingGroup a fully-fledged
-  // RouteProvider, so we can start registering routes directly with an
-  // AgentSchedulingGroup rather than ChildThreadImpl.
-  ToImpl(render_thread_).GetRoute(routing_id, std::move(receiver));
+  DCHECK(receiver.is_valid());
+  associated_interface_provider_receivers_.Add(this, std::move(receiver),
+                                               routing_id);
 }
 
 void AgentSchedulingGroup::GetAssociatedInterface(
     const std::string& name,
     mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterface>
         receiver) {
-  // TODO(crbug.com/1111231): Make AgentSchedulingGroup a fully-fledged
-  // AssociatedInterfaceProvider, so we can start associating interfaces
-  // directly with the AgentSchedulingGroup interface.
-  ToImpl(render_thread_).GetAssociatedInterface(name, std::move(receiver));
+  int32_t routing_id =
+      associated_interface_provider_receivers_.current_context();
+  IPC::Listener* listener = ToImpl(render_thread_).GetListener(routing_id);
+  if (listener)
+    listener->OnAssociatedInterfaceRequest(name, receiver.PassHandle());
 }
 
 }  // namespace content
diff --git a/content/renderer/agent_scheduling_group.h b/content/renderer/agent_scheduling_group.h
index 4ae51353..033182af 100644
--- a/content/renderer/agent_scheduling_group.h
+++ b/content/renderer/agent_scheduling_group.h
@@ -10,6 +10,7 @@
 #include "content/common/associated_interfaces.mojom.h"
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/associated_receiver_set.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -61,7 +62,8 @@
   void AddRoute(int32_t routing_id, IPC::Listener* listener);
   void RemoveRoute(int32_t routing_id);
 
-  mojom::RouteProvider* GetRemoteRouteProvider();
+  // This is virtual only for unit tests.
+  virtual mojom::RouteProvider* GetRemoteRouteProvider();
 
  private:
   // `MaybeAssociatedReceiver` and `MaybeAssociatedRemote` are temporary helper
@@ -99,6 +101,7 @@
         mojo::PendingAssociatedRemote<mojom::AgentSchedulingGroupHost>
             host_remote);
     ~MaybeAssociatedRemote();
+    mojom::AgentSchedulingGroupHost* get();
 
    private:
     absl::variant<mojo::Remote<mojom::AgentSchedulingGroupHost>,
@@ -118,6 +121,9 @@
       const FrameReplicationState& replicated_state,
       const base::UnguessableToken& frame_token,
       const base::UnguessableToken& devtools_frame_token) override;
+  void BindAssociatedRouteProvider(
+      mojo::PendingAssociatedRemote<mojom::RouteProvider> remote,
+      mojo::PendingAssociatedReceiver<mojom::RouteProvider> receiever) override;
 
   // mojom::RouteProvider
   void GetRoute(
@@ -140,6 +146,20 @@
   // Remote stub of mojom::AgentSchedulingGroupHost, used for sending calls to
   // the (browser-side) AgentSchedulingGroupHost.
   MaybeAssociatedRemote host_remote_;
+
+  // The |mojom::RouteProvider| mojo pair to setup
+  // |blink::AssociatedInterfaceProvider| routes between us and the browser-side
+  // |AgentSchedulingGroup|.
+  mojo::AssociatedRemote<mojom::RouteProvider> remote_route_provider_;
+  mojo::AssociatedReceiver<mojom::RouteProvider> route_provider_receiver_{this};
+
+  // The `blink::mojom::AssociatedInterfaceProvider` receiver set that *all*
+  // browser-side `blink::AssociatedInterfaceProvider` objects own a remote to.
+  // `AgentSchedulingGroupHost` will be responsible for routing each associated
+  // interface request to the appropriate renderer object.
+  mojo::AssociatedReceiverSet<blink::mojom::AssociatedInterfaceProvider,
+                              int32_t>
+      associated_interface_provider_receivers_;
 };
 
 }  // namespace content
diff --git a/content/renderer/mock_agent_scheduling_group.cc b/content/renderer/mock_agent_scheduling_group.cc
new file mode 100644
index 0000000..28f240ca
--- /dev/null
+++ b/content/renderer/mock_agent_scheduling_group.cc
@@ -0,0 +1,33 @@
+// 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 "content/renderer/mock_agent_scheduling_group.h"
+
+#include "base/no_destructor.h"
+#include "content/renderer/render_thread_impl.h"
+
+namespace content {
+
+MockAgentSchedulingGroup::MockAgentSchedulingGroup(
+    RenderThread& render_thread,
+    mojo::PendingAssociatedRemote<mojom::AgentSchedulingGroupHost> host_remote,
+    mojo::PendingAssociatedReceiver<mojom::AgentSchedulingGroup> receiver,
+    base::OnceCallback<void(const AgentSchedulingGroup*)>
+        mojo_disconnect_handler)
+    : AgentSchedulingGroup(render_thread,
+                           std::move(host_remote),
+                           std::move(receiver),
+                           std::move(mojo_disconnect_handler)) {}
+
+mojom::RouteProvider* MockAgentSchedulingGroup::GetRemoteRouteProvider() {
+  DCHECK(!RenderThreadImpl::current());
+  static base::NoDestructor<mojo::Remote<mojom::RouteProvider>> static_remote;
+  if (!static_remote->is_bound()) {
+    ignore_result(static_remote->BindNewPipeAndPassReceiver());
+  }
+  DCHECK(static_remote->is_bound());
+  return static_remote->get();
+}
+
+}  // namespace content
diff --git a/content/renderer/mock_agent_scheduling_group.h b/content/renderer/mock_agent_scheduling_group.h
new file mode 100644
index 0000000..f927d8d
--- /dev/null
+++ b/content/renderer/mock_agent_scheduling_group.h
@@ -0,0 +1,40 @@
+// 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 CONTENT_RENDERER_MOCK_AGENT_SCHEDULING_GROUP_H_
+#define CONTENT_RENDERER_MOCK_AGENT_SCHEDULING_GROUP_H_
+
+#include "base/callback.h"
+#include "content/common/associated_interfaces.mojom.h"
+#include "content/common/content_export.h"
+#include "content/renderer/agent_scheduling_group.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+namespace content {
+
+class RenderThread;
+
+// A mock of `AgentSchedulingGroup`, that exists only to provide some test-only
+// overrides of the base class methods. Meant to be used in unit tests, where
+// the `AgentSchedulingGroup` is not actually wired up to its corresponding host
+// in the browser process.
+class MockAgentSchedulingGroup : public AgentSchedulingGroup {
+ public:
+  // `mojo_disconnect_handler` is an optional callback that will be called with
+  // `this` when `receiver` is disconnected.
+  MockAgentSchedulingGroup(
+      RenderThread& render_thread,
+      mojo::PendingAssociatedRemote<mojom::AgentSchedulingGroupHost>
+          host_remote,
+      mojo::PendingAssociatedReceiver<mojom::AgentSchedulingGroup> receiver,
+      base::OnceCallback<void(const AgentSchedulingGroup*)>
+          mojo_disconnect_handler);
+
+  mojom::RouteProvider* GetRemoteRouteProvider() override;
+};
+
+}  // namespace content
+
+#endif
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index 96f49dd3..9346c39e 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -1247,9 +1247,6 @@
   if (desired_fullscreen_state_ || view_data_.is_fullscreen) {
     bool is_fullscreen_element = container_->IsFullscreenElement();
     if (!view_data_.is_fullscreen && desired_fullscreen_state_ &&
-        render_frame()
-            ->GetLocalRootRenderWidget()
-            ->IsFullscreenGrantedForFrame() &&
         is_fullscreen_element) {
       // Entered fullscreen. Only possible via SetFullscreen().
       view_data_.is_fullscreen = true;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 0998f754..0a63771 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -630,8 +630,6 @@
           URLLoaderThrottleProviderType::kFrame);
 
   GetAssociatedInterfaceRegistry()->AddInterface(base::BindRepeating(
-      &RenderThreadImpl::OnRouteProviderReceiver, base::Unretained(this)));
-  GetAssociatedInterfaceRegistry()->AddInterface(base::BindRepeating(
       &RenderThreadImpl::OnRendererInterfaceReceiver, base::Unretained(this)));
 
   const base::CommandLine& command_line =
@@ -950,16 +948,6 @@
   return video_frame_compositor_task_runner_;
 }
 
-mojom::RouteProvider* RenderThreadImpl::GetRemoteRouteProvider(
-    util::PassKey<AgentSchedulingGroup>) {
-  if (!remote_route_provider_) {
-    DCHECK(GetChannel());
-    GetChannel()->GetRemoteAssociatedInterface(&remote_route_provider_);
-  }
-
-  return remote_route_provider_.get();
-}
-
 void RenderThreadImpl::InitializeWebKit(mojo::BinderMap* binders) {
   DCHECK(!blink_platform_impl_);
 
@@ -1891,26 +1879,6 @@
   }
 }
 
-void RenderThreadImpl::GetRoute(
-    int32_t routing_id,
-    mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterfaceProvider>
-        receiver) {
-  associated_interface_provider_receivers_.Add(this, std::move(receiver),
-                                               routing_id);
-}
-
-void RenderThreadImpl::GetAssociatedInterface(
-    const std::string& name,
-    mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterface>
-        receiver) {
-  int32_t routing_id =
-      associated_interface_provider_receivers_.current_context();
-  // We delegate to ChildThreadImpl when we actually need to communicate with
-  // IPC::Listeners, since it owns the router.
-  ChildThreadImpl::GetAssociatedInterface(routing_id, name,
-                                          std::move(receiver));
-}
-
 scoped_refptr<base::SingleThreadTaskRunner>
 RenderThreadImpl::GetMediaThreadTaskRunner() {
   DCHECK(main_thread_runner()->BelongsToCurrentThread());
@@ -2100,14 +2068,6 @@
       v8_memory_pressure_level);
 }
 
-void RenderThreadImpl::OnRouteProviderReceiver(
-    mojo::PendingAssociatedReceiver<mojom::RouteProvider> receiver) {
-  DCHECK(!route_provider_receiver_.is_bound());
-  route_provider_receiver_.Bind(
-      std::move(receiver),
-      GetWebMainThreadScheduler()->DeprecatedDefaultTaskRunner());
-}
-
 void RenderThreadImpl::OnRendererInterfaceReceiver(
     mojo::PendingAssociatedReceiver<mojom::Renderer> receiver) {
   DCHECK(!renderer_receiver_.is_bound());
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index cab50f7e..b741979 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -124,8 +124,6 @@
     : public RenderThread,
       public ChildThreadImpl,
       public mojom::Renderer,
-      public mojom::RouteProvider,
-      public blink::mojom::AssociatedInterfaceProvider,
       public viz::mojom::CompositingModeWatcher,
       public CompositorDependencies {
  public:
@@ -427,9 +425,6 @@
     video_frame_compositor_task_runner_ = task_runner;
   }
 
-  mojom::RouteProvider* GetRemoteRouteProvider(
-      util::PassKey<AgentSchedulingGroup>) override;
-
  private:
   friend class RenderThreadImplBrowserTest;
   friend class AgentSchedulingGroup;
@@ -494,18 +489,6 @@
   void OnMemoryPressure(
       base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
 
-  // mojom::RouteProvider implementation:
-  void GetRoute(
-      int32_t routing_id,
-      mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterfaceProvider>
-          receiver) override;
-
-  // blink::mojom::AssociatedInterfaceProvider implementation:
-  void GetAssociatedInterface(
-      const std::string& name,
-      mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterface>
-          receiver) override;
-
   bool RendererIsHidden() const;
   void OnRendererHidden();
   void OnRendererVisible();
@@ -528,8 +511,6 @@
   std::unique_ptr<viz::SyntheticBeginFrameSource>
   CreateSyntheticBeginFrameSource();
 
-  void OnRouteProviderReceiver(
-      mojo::PendingAssociatedReceiver<mojom::RouteProvider> receiver);
   void OnRendererInterfaceReceiver(
       mojo::PendingAssociatedReceiver<mojom::Renderer> receiver);
 
@@ -631,12 +612,6 @@
 
   mojo::AssociatedRemote<mojom::RendererHost> renderer_host_;
 
-  mojo::AssociatedReceiver<mojom::RouteProvider> route_provider_receiver_{this};
-  mojo::AssociatedReceiverSet<blink::mojom::AssociatedInterfaceProvider,
-                              int32_t>
-      associated_interface_provider_receivers_;
-  mojo::AssociatedRemote<mojom::RouteProvider> remote_route_provider_;
-
   blink::AssociatedInterfaceRegistry associated_interfaces_;
 
   mojo::AssociatedReceiver<mojom::Renderer> renderer_receiver_{this};
diff --git a/content/renderer/render_thread_impl_browsertest.cc b/content/renderer/render_thread_impl_browsertest.cc
index dcc8274..c6161e3 100644
--- a/content/renderer/render_thread_impl_browsertest.cc
+++ b/content/renderer/render_thread_impl_browsertest.cc
@@ -266,18 +266,6 @@
   DISALLOW_COPY_AND_ASSIGN(RenderThreadImplBrowserTest);
 };
 
-// Check that InputHandlerManager outlives compositor thread because it uses
-// raw pointers to post tasks.
-// Disabled under LeakSanitizer due to memory leaks. http://crbug.com/348994
-// Disabled on Windows due to flakiness: http://crbug.com/728034.
-#if defined(OS_WIN)
-#define MAYBE_InputHandlerManagerDestroyedAfterCompositorThread \
-  DISABLED_InputHandlerManagerDestroyedAfterCompositorThread
-#else
-#define MAYBE_InputHandlerManagerDestroyedAfterCompositorThread \
-  InputHandlerManagerDestroyedAfterCompositorThread
-#endif
-
 // Disabled under LeakSanitizer due to memory leaks.
 TEST_F(RenderThreadImplBrowserTest,
        WILL_LEAK(NonResourceDispatchIPCTasksDontGoThroughScheduler)) {
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index e60bd43..bfed755 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -478,10 +478,4 @@
   }
 }
 
-bool RenderWidget::IsFullscreenGrantedForFrame() {
-  if (!for_frame())
-    return false;
-  return GetFrameWidget()->IsFullscreenGranted();
-}
-
 }  // namespace content
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 970adac7..5f2b9ee 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -221,9 +221,6 @@
       base::OnceCallback<void(const gfx::PresentationFeedback&)>;
   virtual void RequestPresentation(PresentationTimeCallback callback);
 
-  // Determines if fullscreen is granted for the frame.
-  bool IsFullscreenGrantedForFrame();
-
  protected:
   // Destroy the RenderWidget. The |widget| is the owning pointer of |this|.
   virtual void Close(std::unique_ptr<RenderWidget> widget);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 166d63cf..33b3f3fb 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -253,6 +253,8 @@
     "../public/test/web_contents_tester.h",
     "../public/test/web_ui_browsertest_util.cc",
     "../public/test/web_ui_browsertest_util.h",
+    "../renderer/mock_agent_scheduling_group.cc",
+    "../renderer/mock_agent_scheduling_group.h",
     "content_browser_consistency_checker.cc",
     "content_browser_consistency_checker.h",
     "content_test_suite.cc",
@@ -632,9 +634,13 @@
     data_deps = [
       ":telemetry_gpu_integration_test_scripts_only",
       ":telemetry_gpu_integration_test_support",
-      "//fuchsia/engine:web_engine_runner",
       "//fuchsia/engine:web_engine_shell",
+      "//fuchsia/engine:web_engine_with_webui",
     ]
+
+    # TODO(crbug.com/1092729): Remove once Catapult is migrated to use
+    # `web_engine_with_webui`.
+    data_deps += [ "//fuchsia/engine:web_engine" ]
   }
 }
 
diff --git a/content/test/OWNERS b/content/test/OWNERS
index a14569b..d1693eb 100644
--- a/content/test/OWNERS
+++ b/content/test/OWNERS
@@ -24,6 +24,9 @@
 # Trust Tokens-related files.
 per-file *trust_token*=file://services/network/trust_tokens/OWNERS
 
+# Fuchsia related files.
+per-file *fuchsia*=file://build/fuchsia/OWNERS
+
 # Anyone can add rules to include new test files.
 per-file BUILD.gn=*
 
diff --git a/content/test/gpu/run_gpu_integration_test_fuchsia.py b/content/test/gpu/run_gpu_integration_test_fuchsia.py
index 6269808..0e87298 100755
--- a/content/test/gpu/run_gpu_integration_test_fuchsia.py
+++ b/content/test/gpu/run_gpu_integration_test_fuchsia.py
@@ -43,7 +43,9 @@
     temp_log_file = True
     additional_target_args['system_log_file'] = args.system_log_file
 
-  package_names = ['web_engine', 'web_engine_shell']
+  # TODO(crbug.com/1092729): Remove 'web_engine' when Catapult is migrated
+  # to use "web_engine_with_webui".
+  package_names = ['web_engine', 'web_engine_with_webui', 'web_engine_shell']
   web_engine_dir = os.path.join(args.out_dir, 'gen', 'fuchsia', 'engine')
   gpu_script = [
       os.path.join(path_util.GetChromiumSrcDir(), 'content', 'test', 'gpu',
diff --git a/device/vr/openxr/openxr_defs.h b/device/vr/openxr/openxr_defs.h
index 2fd969ab..e887af4 100644
--- a/device/vr/openxr/openxr_defs.h
+++ b/device/vr/openxr/openxr_defs.h
@@ -10,6 +10,7 @@
     "XR_EXT_samsung_odyssey_controller";
 constexpr char kExtHPMixedRealityControllerExtensionName[] =
     "XR_EXT_hp_mixed_reality_controller";
+constexpr char kMSFTHandInteractionExtensionName[] = "XR_MSFT_hand_interaction";
 
 }  // namespace device
 
diff --git a/device/vr/openxr/openxr_interaction_profiles.h b/device/vr/openxr/openxr_interaction_profiles.h
index 9c32aa9..6222870 100644
--- a/device/vr/openxr/openxr_interaction_profiles.h
+++ b/device/vr/openxr/openxr_interaction_profiles.h
@@ -28,7 +28,8 @@
   kHTCVive = 4,
   kSamsungOdyssey = 5,
   kHPReverbG2 = 6,
-  kCount = 7,
+  kHandSelect = 7,
+  kCount = 8,
 };
 
 enum class OpenXrButtonType {
@@ -94,6 +95,7 @@
 // Valve index controller.
 // HTC vive controller
 // HP Reverb G2 controller
+// MSFT Hand Interaction
 // Declare OpenXR input profile bindings for other runtimes when they become
 // available.
 constexpr const char* kMicrosoftMotionInputProfiles[] = {
@@ -117,6 +119,9 @@
 constexpr const char* kHPReverbG2InputProfiles[] = {
     "hp-mixed-reality", "oculus-touch", "generic-trigger-squeeze"};
 
+constexpr const char* kGenericHandSelectInputProfile[] = {
+    "generic-hand-select"};
+
 constexpr OpenXrButtonPathMap kMicrosoftMotionControllerButtonPathMaps[] = {
     {OpenXrButtonType::kTrigger,
      {
@@ -274,6 +279,12 @@
      1},
 };
 
+constexpr OpenXrButtonPathMap kGenericHandSelectButtonPathMaps[] = {
+    {OpenXrButtonType::kTrigger,
+     {{OpenXrButtonActionType::kValue, "/input/select/value"}},
+     1},
+};
+
 constexpr OpenXrAxisPathMap kMicrosoftMotionControllerAxisPathMaps[] = {
     {OpenXrAxisType::kTrackpad, "/input/trackpad"},
     {OpenXrAxisType::kThumbstick, "/input/thumbstick"},
@@ -396,11 +407,30 @@
     base::size(kHPReverbG2ControllerAxisPathMaps)};
 
 constexpr OpenXrControllerInteractionProfile
+    kHandInteractionMSFTInteractionProfile = {
+        OpenXrInteractionProfileType::kHandSelect,
+        "/interaction_profiles/microsoft/hand_interaction",
+        kMSFTHandInteractionExtensionName,
+        GamepadMapping::kNone,
+        kGenericHandSelectInputProfile,
+        base::size(kGenericHandSelectInputProfile),
+        kGenericHandSelectButtonPathMaps,
+        base::size(kGenericHandSelectButtonPathMaps),
+        kGenericHandSelectButtonPathMaps,
+        base::size(kGenericHandSelectButtonPathMaps),
+        nullptr,
+        0};
+
+constexpr OpenXrControllerInteractionProfile
     kOpenXrControllerInteractionProfiles[] = {
-        kMicrosoftMotionInteractionProfile, kKHRSimpleInteractionProfile,
-        kOculusTouchInteractionProfile,     kValveIndexInteractionProfile,
-        kHTCViveInteractionProfile,         kSamsungOdysseyInteractionProfile,
-        kHPReverbG2InteractionProfile};
+        kMicrosoftMotionInteractionProfile,
+        kKHRSimpleInteractionProfile,
+        kOculusTouchInteractionProfile,
+        kValveIndexInteractionProfile,
+        kHTCViveInteractionProfile,
+        kSamsungOdysseyInteractionProfile,
+        kHPReverbG2InteractionProfile,
+        kHandInteractionMSFTInteractionProfile};
 
 }  // namespace device
 
diff --git a/device/vr/openxr/openxr_util.cc b/device/vr/openxr/openxr_util.cc
index fdfc66d4..4d727d1 100644
--- a/device/vr/openxr/openxr_util.cc
+++ b/device/vr/openxr/openxr_util.cc
@@ -125,6 +125,13 @@
     extensions.push_back(kExtHPMixedRealityControllerExtensionName);
   }
 
+  const bool handInteractionExtensionSupported =
+      extension_enumeration.ExtensionSupported(
+          kMSFTHandInteractionExtensionName);
+  if (handInteractionExtensionSupported) {
+    extensions.push_back(kMSFTHandInteractionExtensionName);
+  }
+
   instance_create_info.enabledExtensionCount =
       static_cast<uint32_t>(extensions.size());
   instance_create_info.enabledExtensionNames = extensions.data();
diff --git a/docs/design/sandbox.md b/docs/design/sandbox.md
index a73501f8..d3a6282 100644
--- a/docs/design/sandbox.md
+++ b/docs/design/sandbox.md
@@ -362,6 +362,13 @@
 * Compiler/Linker opt-in, not a run-time policy opt-in.  See
 [MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/mt637065(v=vs.85).aspx).
 
+#### CET Shadow Stack:
+
+* Only in Insider Builds of Windows 10 yet.
+* It's being evaluated and not enabled for any processes.  See
+[ticket](https://bugs.chromium.org/p/chromium/issues/detail?id=1136224),
+[MSDN](https://docs.microsoft.com/en-us/cpp/build/reference/cetcompat?view=vs-2019).
+
 #### Disable Font Loading:
 
 * &gt;= Win10
diff --git a/fuchsia/cipd/BUILD.gn b/fuchsia/cipd/BUILD.gn
index a59fd83..3e60ead 100644
--- a/fuchsia/cipd/BUILD.gn
+++ b/fuchsia/cipd/BUILD.gn
@@ -95,11 +95,13 @@
 
   deps = [
     "//fuchsia/engine:web_engine",
+    "//fuchsia/engine:web_engine_with_webui",
     "//fuchsia/runners:web_runner_pkg",
   ]
 
   sources = [
     "${root_gen_dir}/fuchsia/engine/web_engine/web_engine.far",
+    "${root_gen_dir}/fuchsia/engine/web_engine_with_webui/web_engine_with_webui.far",
     "${root_gen_dir}/fuchsia/runners/web_runner/web_runner.far",
   ]
 }
diff --git a/fuchsia/engine/BUILD.gn b/fuchsia/engine/BUILD.gn
index 3486d29..a78c7441 100644
--- a/fuchsia/engine/BUILD.gn
+++ b/fuchsia/engine/BUILD.gn
@@ -14,17 +14,6 @@
   defines = [ "WEB_ENGINE_IMPLEMENTATION" ]
 }
 
-declare_args() {
-  # If set, includes assets served under chrome://resources in web_engine.pak.
-  # They are required by some test-oriented diagnostic views like
-  # chrome://gpu.
-  # Including the resources will increase the application size, so this value
-  # should be left unset for release builds.
-  # TODO(crbug.com/1082420): change default to 'false' once all bots that run
-  # GPU integration tests set this flag to 'true'.
-  include_webui_resources = !is_official_build
-}
-
 mojom("mojom") {
   sources = [
     "cast_streaming_session.mojom",
@@ -56,10 +45,6 @@
     "$root_gen_dir/ui/strings/ui_strings_en-US.pak",
   ]
 
-  if (include_webui_resources) {
-    sources += [ "$root_gen_dir/ui/resources/webui_resources.pak" ]
-  }
-
   deps = [
     "//components/resources:components_resources",
     "//components/strings",
@@ -240,22 +225,49 @@
   visibility = [ ":*" ]
 }
 
-cr_fuchsia_package("web_engine") {
-  binary = ":web_engine_exe"
-  manifest = "context_provider.cmx"
-  component_name_override = "context_provider"
-
-  excluded_files = [
-    "lib/libswiftshader_libEGL.so",
-    "lib/libswiftshader_libGLESv2.so",
-  ]
+source_set("webui_resources") {
+  data = [ "$root_gen_dir/ui/resources/webui_resources.pak" ]
+  deps = [ "//ui/resources" ]
 }
 
-fuchsia_package_runner("web_engine_runner") {
+template("web_engine_package") {
+  cr_fuchsia_package(target_name) {
+    binary = ":web_engine_exe"
+    manifest = "context_provider.cmx"
+    component_name_override = "context_provider"
+
+    if (invoker.include_webui_resources_pak) {
+      deps = [ ":webui_resources" ]
+    }
+
+    excluded_files = [
+      "lib/libswiftshader_libEGL.so",
+      "lib/libswiftshader_libGLESv2.so",
+    ]
+  }
+}
+
+web_engine_package("web_engine") {
+  # TODO(crbug.com/2424514): Set to "false" once telemetry tests are migrated to
+  # use `web_engine_with_webui`.
+  include_webui_resources_pak = !is_official_build
+}
+
+fuchsia_package_runner("web_engine_installer") {
   package = ":web_engine"
   install_only = true
 }
 
+# Build a WebEngine package that contains WebUI static resources.
+web_engine_package("web_engine_with_webui") {
+  include_webui_resources_pak = true
+}
+
+fuchsia_package_runner("web_engine_with_webui_installer") {
+  package = ":web_engine_with_webui"
+  install_only = true
+}
+
 source_set("browsertest_core") {
   testonly = true
   sources = [
@@ -385,10 +397,16 @@
   testonly = true
   package = ":web_engine_shell_pkg"
   package_name_override = "web_engine_shell"
-  package_deps = [ [
-        ":web_engine",
-        "web_engine",
-      ] ]
+  package_deps = [
+    [
+      ":web_engine",
+      "web_engine",
+    ],
+    [
+      ":web_engine_with_webui",
+      "web_engine_with_webui",
+    ],
+  ]
 }
 
 executable("web_engine_shell_exec") {
diff --git a/fuchsia/engine/test/web_engine_shell.cc b/fuchsia/engine/test/web_engine_shell.cc
index a2d06f69..f326b7bf 100644
--- a/fuchsia/engine/test/web_engine_shell.cc
+++ b/fuchsia/engine/test/web_engine_shell.cc
@@ -22,8 +22,8 @@
 #include "base/message_loop/message_pump_type.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
-#include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/task/single_thread_task_executor.h"
 #include "base/values.h"
 #include "fuchsia/base/init_logging.h"
@@ -37,12 +37,14 @@
 constexpr char kHeadlessSwitch[] = "headless";
 constexpr char kEnableProtectedMediaIdentifier[] =
     "enable-protected-media-identifier";
+constexpr char kWebEnginePackageName[] = "web-engine-package-name";
 
 void PrintUsage() {
   std::cerr << "Usage: "
             << base::CommandLine::ForCurrentProcess()->GetProgram().BaseName()
             << " [--" << kRemoteDebuggingPortSwitch << "] [--"
-            << kHeadlessSwitch << "] URL. [--] [--{extra_flag1}] "
+            << kHeadlessSwitch << "] [--" << kWebEnginePackageName
+            << "=name] URL. [--] [--{extra_flag1}] "
             << "[--{extra_flag2}]" << std::endl
             << "Setting " << kRemoteDebuggingPortSwitch << " to 0 will "
             << "automatically choose an available port." << std::endl
@@ -80,24 +82,32 @@
 }
 
 fuchsia::web::ContextProviderPtr ConnectToContextProvider(
+    base::StringPiece web_engine_package_name_override,
     const base::CommandLine::StringVector& extra_command_line_arguments) {
   sys::ComponentContext* const component_context =
       base::ComponentContextForProcess();
 
   // If there are no additional command-line arguments then use the
   // system instance of the ContextProvider.
-  if (extra_command_line_arguments.empty()) {
+  if (extra_command_line_arguments.empty() &&
+      web_engine_package_name_override.empty()) {
     return component_context->svc()->Connect<fuchsia::web::ContextProvider>();
   }
 
+  base::StringPiece web_engine_package_name =
+      web_engine_package_name_override.empty()
+          ? "web_engine"
+          : web_engine_package_name_override;
+
   // Launch a private ContextProvider instance, with the desired command-line
   // arguments.
   fuchsia::sys::LauncherPtr launcher;
   component_context->svc()->Connect(launcher.NewRequest());
 
   fuchsia::sys::LaunchInfo launch_info;
-  launch_info.url =
-      "fuchsia-pkg://fuchsia.com/web_engine#meta/context_provider.cmx";
+  launch_info.url = base::StringPrintf(
+      "fuchsia-pkg://fuchsia.com/%s#meta/context_provider.cmx",
+      web_engine_package_name.data());
   launch_info.arguments = extra_command_line_arguments;
   fidl::InterfaceHandle<fuchsia::io::Directory> service_directory;
   launch_info.directory_request = service_directory.NewRequest().TakeChannel();
@@ -148,7 +158,9 @@
   additional_args.erase(additional_args.begin());
 
   fuchsia::web::ContextProviderPtr web_context_provider =
-      ConnectToContextProvider(additional_args);
+      ConnectToContextProvider(
+          command_line->GetSwitchValueASCII(kWebEnginePackageName),
+          additional_args);
 
   // Set up the content directory fuchsia-pkg://shell-data/, which will host
   // the files stored under //fuchsia/engine/test/shell_data.
diff --git a/fuchsia/engine/web_engine_main_delegate.cc b/fuchsia/engine/web_engine_main_delegate.cc
index f3eccc76..2265ca9d 100644
--- a/fuchsia/engine/web_engine_main_delegate.cc
+++ b/fuchsia/engine/web_engine_main_delegate.cc
@@ -9,6 +9,7 @@
 #include "base/base_paths.h"
 #include "base/base_paths_fuchsia.h"
 #include "base/command_line.h"
+#include "base/files/file_util.h"
 #include "base/path_service.h"
 #include "content/public/common/content_switches.h"
 #include "fuchsia/base/init_logging.h"
@@ -24,12 +25,23 @@
 
 WebEngineMainDelegate* g_current_web_engine_main_delegate = nullptr;
 
-void InitializeResourceBundle() {
-  base::FilePath pak_file;
-  bool result = base::PathService::Get(base::DIR_ASSETS, &pak_file);
+void InitializeResources() {
+  constexpr char kWebEnginePakPath[] = "web_engine.pak";
+  constexpr char kWebUiResourcesPakPath[] = "ui/resources/webui_resources.pak";
+
+  base::FilePath asset_root;
+  bool result = base::PathService::Get(base::DIR_ASSETS, &asset_root);
   DCHECK(result);
-  pak_file = pak_file.Append("web_engine.pak");
-  ui::ResourceBundle::InitSharedInstanceWithPakPath(pak_file);
+  ui::ResourceBundle::InitSharedInstanceWithPakPath(
+      asset_root.Append(kWebEnginePakPath));
+
+  // Conditionally load WebUI resource PAK if visible from namespace.
+  base::FilePath webui_resources_path =
+      asset_root.Append(kWebUiResourcesPakPath);
+  if (base::PathExists(webui_resources_path)) {
+    ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
+        webui_resources_path, ui::SCALE_FACTOR_NONE);
+  }
 }
 
 }  // namespace
@@ -64,7 +76,7 @@
 }
 
 void WebEngineMainDelegate::PreSandboxStartup() {
-  InitializeResourceBundle();
+  InitializeResources();
 }
 
 int WebEngineMainDelegate::RunProcess(
diff --git a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc
index ec279ebf..f0d0c2e4a 100644
--- a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc
+++ b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc
@@ -71,7 +71,9 @@
   return std::string();
 }
 
-std::string UIThreadSearchTermsData::GetSuggestClient() const {
+std::string UIThreadSearchTermsData::GetSuggestClient(bool from_ntp) const {
+  // IOS does not send non-searchbox suggest requests from NTP at this time.
+  DCHECK(!from_ntp);
   DCHECK(thread_checker_.CalledOnValidThread());
   return "chrome";
 }
diff --git a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.h b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.h
index 75cfcaa..d637738 100644
--- a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.h
+++ b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.h
@@ -22,7 +22,7 @@
   std::string GetApplicationLocale() const override;
   base::string16 GetRlzParameterValue(bool from_app_list) const override;
   std::string GetSearchClient() const override;
-  std::string GetSuggestClient() const override;
+  std::string GetSuggestClient(bool from_ntp) const override;
   std::string GetSuggestRequestIdentifier() const override;
   std::string GoogleImageSearchSource() const override;
 
diff --git a/mojo/core/message_pipe_dispatcher.cc b/mojo/core/message_pipe_dispatcher.cc
index e17fdab..980d01ce 100644
--- a/mojo/core/message_pipe_dispatcher.cc
+++ b/mojo/core/message_pipe_dispatcher.cc
@@ -199,42 +199,51 @@
 }
 
 MojoResult MessagePipeDispatcher::SetQuota(MojoQuotaType type, uint64_t limit) {
-  base::AutoLock lock(signal_lock_);
+  base::Optional<uint64_t> new_ack_request_interval;
+  {
+    base::AutoLock lock(signal_lock_);
+    switch (type) {
+      case MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH:
+        if (limit == MOJO_QUOTA_LIMIT_NONE)
+          receive_queue_length_limit_.reset();
+        else
+          receive_queue_length_limit_ = limit;
+        break;
 
-  switch (type) {
-    case MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH:
-      if (limit == MOJO_QUOTA_LIMIT_NONE)
-        receive_queue_length_limit_.reset();
-      else
-        receive_queue_length_limit_ = limit;
-      break;
+      case MOJO_QUOTA_TYPE_RECEIVE_QUEUE_MEMORY_SIZE:
+        if (limit == MOJO_QUOTA_LIMIT_NONE)
+          receive_queue_memory_size_limit_.reset();
+        else
+          receive_queue_memory_size_limit_ = limit;
+        break;
 
-    case MOJO_QUOTA_TYPE_RECEIVE_QUEUE_MEMORY_SIZE:
-      if (limit == MOJO_QUOTA_LIMIT_NONE)
-        receive_queue_memory_size_limit_.reset();
-      else
-        receive_queue_memory_size_limit_ = limit;
-      break;
+      case MOJO_QUOTA_TYPE_UNREAD_MESSAGE_COUNT:
+        if (limit == MOJO_QUOTA_LIMIT_NONE) {
+          unread_message_count_limit_.reset();
+          new_ack_request_interval = 0;
+        } else {
+          unread_message_count_limit_ = limit;
+          // Setting the acknowledge request interval for the port to half the
+          // unread quota limit, means the ack roundtrip has half the window to
+          // catch up with sent messages. In other words, if the producer is
+          // producing messages at a steady rate of limit/2 packets per message
+          // round trip or lower, the quota limit won't be exceeded. This is
+          // assuming the consumer is consuming messages at the same rate.
+          new_ack_request_interval = (limit + 1) / 2;
+        }
+        break;
 
-    case MOJO_QUOTA_TYPE_UNREAD_MESSAGE_COUNT:
-      if (limit == MOJO_QUOTA_LIMIT_NONE) {
-        unread_message_count_limit_.reset();
-        node_controller_->node()->SetAcknowledgeRequestInterval(port_, 0);
-      } else {
-        unread_message_count_limit_ = limit;
-        // Setting the acknowledge request interval for the port to half the
-        // unread quota limit, means the ack roundtrip has half the window to
-        // catch up with sent messages. In other words, if the producer is
-        // producing messages at a steady rate of limit/2 packets per message
-        // round trip or lower, the quota limit won't be exceeded. This is
-        // assuming the consumer is consuming messages at the same rate.
-        node_controller_->node()->SetAcknowledgeRequestInterval(
-            port_, (limit + 1) / 2);
-      }
-      break;
+      default:
+        return MOJO_RESULT_INVALID_ARGUMENT;
+    }
+  }
 
-    default:
-      return MOJO_RESULT_INVALID_ARGUMENT;
+  if (new_ack_request_interval.has_value()) {
+    // NOTE: It is not safe to call into SetAcknowledgeRequestInterval while
+    // holding a `signal_lock_`, as it may re-enter this object when the peer is
+    // in the same process.
+    node_controller_->node()->SetAcknowledgeRequestInterval(
+        port_, *new_ack_request_interval);
   }
 
   return MOJO_RESULT_OK;
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index cde2b503..04e817fb 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -2247,6 +2247,12 @@
 // }
 EVENT_TYPE(QUIC_SESSION_ATTEMPTING_TO_PROCESS_UNDECRYPTABLE_PACKET)
 
+// Session has updated to the next set of 1-RTT keys.
+// {
+//   "reason": <the reason the key update was triggered>
+// }
+EVENT_TYPE(QUIC_SESSION_KEY_UPDATE)
+
 // ------------------------------------------------------------------------
 // QuicHttpStream
 // ------------------------------------------------------------------------
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index cbb42af..978011da 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -73,12 +73,6 @@
 
 const size_t kMinRetryTimeForDefaultNetworkSecs = 1;
 
-// Default value for maximum number of consecutive pings that can be sent
-// with aggressive initial retransmittable on wire timeout if there is no new
-// data received. After which, the timeout will be exponentially back off until
-// exceeds the default ping timeout.
-const int kDefaultMaxAggressiveRetransmittableOnWirePingCount = 200;
-
 // Maximum RTT time for this session when set initial timeout for probing
 // network.
 const int kDefaultRTTMilliSecs = 300;
@@ -135,6 +129,10 @@
   }
 }
 
+void LogMigrateToSocketStatus(bool success) {
+  UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.MigrateToSocketSuccess", success);
+}
+
 void RecordConnectionCloseErrorCode(const quic::QuicConnectionCloseFrame& frame,
                                     quic::ConnectionCloseSource source,
                                     const std::string& hostname,
@@ -865,6 +863,7 @@
       max_allowed_push_id_(max_allowed_push_id),
       attempted_zero_rtt_(false),
       num_pings_sent_(0),
+      num_migrations_(0),
       push_promise_index_(std::move(push_promise_index)) {
   // Make sure connection migration and goaway on path degrading are not turned
   // on at the same time.
@@ -905,13 +904,6 @@
   if (!retransmittable_on_wire_timeout.IsZero()) {
     connection->set_initial_retransmittable_on_wire_timeout(
         retransmittable_on_wire_timeout);
-    if (GetQuicFlag(
-            FLAGS_quic_max_aggressive_retransmittable_on_wire_ping_count) ==
-        0) {
-      // Set a default value for this flag if no custom value is provided.
-      SetQuicFlag(FLAGS_quic_max_aggressive_retransmittable_on_wire_ping_count,
-                  kDefaultMaxAggressiveRetransmittableOnWirePingCount);
-    }
   }
 }
 
@@ -1875,6 +1867,7 @@
     UMA_HISTOGRAM_LONG_TIMES_100(
         "Net.QuicSession.ConnectionDuration",
         tick_clock_->NowTicks() - connect_timing_.connect_end);
+    UMA_HISTOGRAM_COUNTS_100("Net.QuicSession.NumMigrations", num_migrations_);
   } else {
     if (error == quic::QUIC_PUBLIC_RESET) {
       RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
@@ -2178,11 +2171,14 @@
   // be acquired by connection and used as default on success.
   if (!MigrateToSocket(std::move(socket), std::move(reader),
                        std::move(writer))) {
+    LogMigrateToSocketStatus(false);
     net_log_.AddEvent(
         NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE_AFTER_PROBING);
     return;
   }
 
+  LogMigrateToSocketStatus(true);
+
   // Notify the connection that migration succeeds after probing.
   if (connection()->IsPathDegrading())
     connection()->OnSuccessfulMigrationAfterProbing();
@@ -2190,6 +2186,7 @@
   net_log_.AddEventWithInt64Params(
       NetLogEventType::QUIC_CONNECTION_MIGRATION_SUCCESS_AFTER_PROBING,
       "migrate_to_network", network);
+  num_migrations_++;
   HistogramAndLogMigrationSuccess(connection_id());
   if (network == default_network_) {
     DVLOG(1) << "Client successfully migrated to default network: "
@@ -2498,6 +2495,12 @@
     observer.OnSessionResumedPostPathDegrading(this, current_network);
 }
 
+void QuicChromiumClientSession::OnKeyUpdate(quic::KeyUpdateReason reason) {
+  net_log_.AddEventWithStringParams(NetLogEventType::QUIC_SESSION_KEY_UPDATE,
+                                    "reason",
+                                    quic::KeyUpdateReasonString(reason));
+}
+
 void QuicChromiumClientSession::OnProofValid(
     const quic::QuicCryptoClientConfig::CachedState& cached) {
   DCHECK(cached.proof_valid());
diff --git a/net/quic/quic_chromium_client_session.h b/net/quic/quic_chromium_client_session.h
index 7883a77f..ba9f42b 100644
--- a/net/quic/quic_chromium_client_session.h
+++ b/net/quic/quic_chromium_client_session.h
@@ -567,6 +567,7 @@
                         bool is_connectivity_probe) override;
   void OnPathDegrading() override;
   void OnForwardProgressMadeAfterPathDegrading() override;
+  void OnKeyUpdate(quic::KeyUpdateReason reason) override;
 
   // QuicChromiumPacketReader::Visitor methods:
   void OnReadError(int result, const DatagramClientSocket* socket) override;
@@ -930,6 +931,8 @@
 
   size_t num_pings_sent_;
 
+  size_t num_migrations_;
+
   std::unique_ptr<quic::QuicClientPushPromiseIndex> push_promise_index_;
 
   base::WeakPtrFactory<QuicChromiumClientSession> weak_factory_{this};
diff --git a/net/quic/quic_flags_list.h b/net/quic/quic_flags_list.h
index 4dacd6c..4656981a 100644
--- a/net/quic/quic_flags_list.h
+++ b/net/quic/quic_flags_list.h
@@ -148,13 +148,18 @@
 // and starts a new one.
 QUIC_FLAG(double, FLAGS_quic_ack_aggregation_bandwidth_threshold, 1.0)
 
-// If set to non-zero, the maximum number of consecutive pings that can be sent
-// with aggressive initial retransmittable on wire timeout if there is no new
-// data received. After which, the timeout will be exponentially back off until
+// Maximum number of consecutive pings that can be sent with the aggressive
+// initial retransmittable on the wire timeout if there is no new stream data
+// received. After this limit, the timeout will be doubled each ping until it
 // exceeds the default ping timeout.
 QUIC_FLAG(int32_t,
           FLAGS_quic_max_aggressive_retransmittable_on_wire_ping_count,
-          0)
+          5)
+
+// Maximum number of pings that can be sent with the retransmittable on the wire
+// timeout, over the lifetime of a connection. After this limit, the timeout
+// will be the default ping timeout.
+QUIC_FLAG(int32_t, FLAGS_quic_max_retransmittable_on_wire_ping_count, 1000)
 
 // The maximum congestion window in packets.
 QUIC_FLAG(int32_t, FLAGS_quic_max_congestion_window, 2000)
diff --git a/net/reporting/reporting_header_parser.cc b/net/reporting/reporting_header_parser.cc
index 50b983b..faf2088 100644
--- a/net/reporting/reporting_header_parser.cc
+++ b/net/reporting/reporting_header_parser.cc
@@ -206,8 +206,7 @@
 
   // Remove the client if it has no valid endpoint groups.
   if (parsed_header.empty()) {
-    // TODO(chlily): Pass NIK to cache.
-    cache->RemoveClient(NetworkIsolationKey::Todo(), origin);
+    cache->RemoveClient(network_isolation_key, origin);
     return;
   }
 
diff --git a/net/reporting/reporting_header_parser_unittest.cc b/net/reporting/reporting_header_parser_unittest.cc
index 9d72c04..81de4693 100644
--- a/net/reporting/reporting_header_parser_unittest.cc
+++ b/net/reporting/reporting_header_parser_unittest.cc
@@ -142,9 +142,9 @@
   const url::Origin kOrigin1_ = url::Origin::Create(kUrl1_);
   const GURL kUrl2_ = GURL("https://origin2.test/path");
   const url::Origin kOrigin2_ = url::Origin::Create(kUrl2_);
-  const NetworkIsolationKey kNik_;
+  const NetworkIsolationKey kNik_ = NetworkIsolationKey(kOrigin1_, kOrigin1_);
   const NetworkIsolationKey kOtherNik_ =
-      NetworkIsolationKey(kOrigin1_, kOrigin2_);
+      NetworkIsolationKey(kOrigin2_, kOrigin2_);
   const GURL kUrlEtld_ = GURL("https://co.uk/foo.html/");
   const url::Origin kOriginEtld_ = url::Origin::Create(kUrlEtld_);
   const GURL kEndpoint1_ = GURL("https://endpoint1.test/");
@@ -1440,6 +1440,164 @@
   }
 }
 
+// Invalid advertisements that parse as JSON should remove an endpoint group,
+// while those that don't are ignored.
+TEST_P(ReportingHeaderParserTest, InvalidAdvertisementRemovesEndpointGroup) {
+  std::string invalid_non_json_header = "Goats should wear hats.";
+  std::string invalid_json_header = "\"Goats should wear hats.\"";
+
+  // Without a pre-existing client, neither invalid header does anything.
+
+  ASSERT_EQ(0u, cache()->GetEndpointCount());
+  ParseHeader(kNik_, kUrl1_, invalid_non_json_header);
+  EXPECT_EQ(0u, cache()->GetEndpointCount());
+  if (mock_store()) {
+    mock_store()->Flush();
+    EXPECT_EQ(0,
+              mock_store()->CountCommands(CommandType::ADD_REPORTING_ENDPOINT));
+    EXPECT_EQ(0, mock_store()->CountCommands(
+                     CommandType::ADD_REPORTING_ENDPOINT_GROUP));
+  }
+
+  ASSERT_EQ(0u, cache()->GetEndpointCount());
+  ParseHeader(kNik_, kUrl1_, invalid_json_header);
+  EXPECT_EQ(0u, cache()->GetEndpointCount());
+  if (mock_store()) {
+    mock_store()->Flush();
+    EXPECT_EQ(0,
+              mock_store()->CountCommands(CommandType::ADD_REPORTING_ENDPOINT));
+    EXPECT_EQ(0, mock_store()->CountCommands(
+                     CommandType::ADD_REPORTING_ENDPOINT_GROUP));
+  }
+
+  // Set a header with two endpoint groups.
+  std::vector<ReportingEndpoint::EndpointInfo> endpoints1 = {{kEndpoint1_}};
+  std::vector<ReportingEndpoint::EndpointInfo> endpoints2 = {{kEndpoint2_}};
+  std::string header1 =
+      ConstructHeaderGroupString(MakeEndpointGroup(kGroup1_, endpoints1)) +
+      ", " +
+      ConstructHeaderGroupString(MakeEndpointGroup(kGroup2_, endpoints2));
+  ParseHeader(kNik_, kUrl1_, header1);
+
+  EXPECT_TRUE(ClientExistsInCacheForOrigin(kOrigin1_));
+  EXPECT_EQ(2u, cache()->GetEndpointGroupCountForTesting());
+  EXPECT_TRUE(
+      EndpointGroupExistsInCache(kGroupKey11_, OriginSubdomains::DEFAULT));
+  EXPECT_TRUE(
+      EndpointGroupExistsInCache(kGroupKey12_, OriginSubdomains::DEFAULT));
+  EXPECT_EQ(2u, cache()->GetEndpointCount());
+  if (mock_store()) {
+    mock_store()->Flush();
+    EXPECT_EQ(2,
+              mock_store()->CountCommands(CommandType::ADD_REPORTING_ENDPOINT));
+    EXPECT_EQ(2, mock_store()->CountCommands(
+                     CommandType::ADD_REPORTING_ENDPOINT_GROUP));
+    MockPersistentReportingStore::CommandList expected_commands;
+    expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT,
+                                   kGroupKey11_, kEndpoint1_);
+    expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT,
+                                   kGroupKey12_, kEndpoint2_);
+    expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT_GROUP,
+                                   kGroupKey11_);
+    expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT_GROUP,
+                                   kGroupKey12_);
+    EXPECT_THAT(mock_store()->GetAllCommands(),
+                testing::IsSupersetOf(expected_commands));
+  }
+
+  // Set another header with max_age: 0 to delete one of the groups.
+  std::string header2 = ConstructHeaderGroupString(MakeEndpointGroup(
+                            kGroup1_, endpoints1, OriginSubdomains::DEFAULT,
+                            base::TimeDelta::FromSeconds(0))) +
+                        ", " +
+                        ConstructHeaderGroupString(MakeEndpointGroup(
+                            kGroup2_, endpoints2));  // Other group stays.
+  ParseHeader(kNik_, kUrl1_, header2);
+
+  EXPECT_TRUE(ClientExistsInCacheForOrigin(kOrigin1_));
+  EXPECT_EQ(1u, cache()->GetEndpointGroupCountForTesting());
+
+  // Group was deleted.
+  EXPECT_FALSE(
+      EndpointGroupExistsInCache(kGroupKey11_, OriginSubdomains::DEFAULT));
+  // Other group remains in the cache.
+  EXPECT_TRUE(
+      EndpointGroupExistsInCache(kGroupKey12_, OriginSubdomains::DEFAULT));
+  EXPECT_EQ(1u, cache()->GetEndpointCount());
+  if (mock_store()) {
+    mock_store()->Flush();
+    EXPECT_EQ(2,
+              mock_store()->CountCommands(CommandType::ADD_REPORTING_ENDPOINT));
+    EXPECT_EQ(2, mock_store()->CountCommands(
+                     CommandType::ADD_REPORTING_ENDPOINT_GROUP));
+    EXPECT_EQ(
+        1, mock_store()->CountCommands(CommandType::DELETE_REPORTING_ENDPOINT));
+    EXPECT_EQ(1, mock_store()->CountCommands(
+                     CommandType::DELETE_REPORTING_ENDPOINT_GROUP));
+    MockPersistentReportingStore::CommandList expected_commands;
+    expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT,
+                                   kGroupKey11_, kEndpoint1_);
+    expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
+                                   kGroupKey11_);
+    EXPECT_THAT(mock_store()->GetAllCommands(),
+                testing::IsSupersetOf(expected_commands));
+  }
+
+  // Invalid header values that are not JSON lists (without the outer brackets)
+  // are ignored.
+  ParseHeader(kNik_, kUrl1_, invalid_non_json_header);
+  EXPECT_TRUE(ClientExistsInCacheForOrigin(kOrigin1_));
+  EXPECT_TRUE(
+      EndpointGroupExistsInCache(kGroupKey12_, OriginSubdomains::DEFAULT));
+  EXPECT_EQ(1u, cache()->GetEndpointCount());
+  if (mock_store()) {
+    mock_store()->Flush();
+    EXPECT_EQ(2,
+              mock_store()->CountCommands(CommandType::ADD_REPORTING_ENDPOINT));
+    EXPECT_EQ(2, mock_store()->CountCommands(
+                     CommandType::ADD_REPORTING_ENDPOINT_GROUP));
+    EXPECT_EQ(
+        1, mock_store()->CountCommands(CommandType::DELETE_REPORTING_ENDPOINT));
+    EXPECT_EQ(1, mock_store()->CountCommands(
+                     CommandType::DELETE_REPORTING_ENDPOINT_GROUP));
+    MockPersistentReportingStore::CommandList expected_commands;
+    expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT,
+                                   kGroupKey11_, kEndpoint1_);
+    expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
+                                   kGroupKey11_);
+    EXPECT_THAT(mock_store()->GetAllCommands(),
+                testing::IsSupersetOf(expected_commands));
+  }
+
+  // Invalid headers that do parse as JSON should delete the corresponding
+  // client.
+  ParseHeader(kNik_, kUrl1_, invalid_json_header);
+
+  // Deletion of the last remaining group also deletes the client for this
+  // origin.
+  EXPECT_FALSE(ClientExistsInCacheForOrigin(kOrigin1_));
+  EXPECT_EQ(0u, cache()->GetEndpointGroupCountForTesting());
+  EXPECT_EQ(0u, cache()->GetEndpointCount());
+  if (mock_store()) {
+    mock_store()->Flush();
+    EXPECT_EQ(2,
+              mock_store()->CountCommands(CommandType::ADD_REPORTING_ENDPOINT));
+    EXPECT_EQ(2, mock_store()->CountCommands(
+                     CommandType::ADD_REPORTING_ENDPOINT_GROUP));
+    EXPECT_EQ(1 + 1, mock_store()->CountCommands(
+                         CommandType::DELETE_REPORTING_ENDPOINT));
+    EXPECT_EQ(1 + 1, mock_store()->CountCommands(
+                         CommandType::DELETE_REPORTING_ENDPOINT_GROUP));
+    MockPersistentReportingStore::CommandList expected_commands;
+    expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT,
+                                   kGroupKey12_, kEndpoint2_);
+    expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
+                                   kGroupKey12_);
+    EXPECT_THAT(mock_store()->GetAllCommands(),
+                testing::IsSupersetOf(expected_commands));
+  }
+}
+
 TEST_P(ReportingHeaderParserTest, EvictEndpointsOverPerOriginLimit1) {
   // Set a header with too many endpoints, all in the same group.
   std::vector<ReportingEndpoint::EndpointInfo> endpoints;
diff --git a/services/network/network_service.cc b/services/network/network_service.cc
index a4a2209c..17ee25ad 100644
--- a/services/network/network_service.cc
+++ b/services/network/network_service.cc
@@ -537,13 +537,6 @@
       SplitString(features::kDnsOverHttpsUpgradeDisabledProvidersParam.Get(),
                   ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
 
-  // Because SECURE mode does not allow any fallback, allow multiple retries as
-  // a quick hack to increase the timeout for these requests.
-  // TODO(crbug.com/1105138): Rethink the timeout logic to be less aggressive in
-  // cases where there is no fallback, without needing to make so many retries.
-  if (secure_dns_mode == net::SecureDnsMode::kSecure)
-    overrides.doh_attempts = 3;
-
   host_resolver_manager_->SetDnsConfigOverrides(overrides);
 }
 
diff --git a/services/network/public/mojom/trust_tokens.mojom b/services/network/public/mojom/trust_tokens.mojom
index 3f3bf63f..a6e75a11 100644
--- a/services/network/public/mojom/trust_tokens.mojom
+++ b/services/network/public/mojom/trust_tokens.mojom
@@ -190,5 +190,31 @@
   // can be used to verify Signed Redemption Record (SRR) signatures
   // subsequently provided by the issuer.
   string signed_redemption_record_verification_key;
+
+  // |request_issuance_locally_on| specifies operating systems on which to
+  // divert issuance requests for this issuer to the system (i.e. to request
+  // "platform-provided" tokens)
+  enum Os {
+    kAndroid,
+  };
+  array<Os> request_issuance_locally_on;
+
+  // When specifying that the browser should attempt local issuance on at least
+  // one operating system, issuers could benefit from a couple different
+  // fallback behaviors depending on their particular requirements.
+  //
+  // |unavailable_local_issuance_fallback|'s value specifies what action to take
+  // when both of the following hold simultaneously:
+  // (1) local issuance is specified on at least one OS (i.e.
+  // |request_issuance_locally_on| is nonempty) and
+  // (2) we're not on any of the specified OSes.
+  enum UnavailableLocalIssuanceFallback {
+    // If we're not on a matching OS, instead attempt a standard web
+    // issuance request against the issuance request's destination URL.
+    kWebIssuance,
+    // If we're not on a matching OS, just fail the issuance request.
+    kReturnWithError,
+  };
+  UnavailableLocalIssuanceFallback unavailable_local_issuance_fallback;
 };
 
diff --git a/services/network/trust_tokens/test/trust_token_key_commitment_parser_fuzzer.dict b/services/network/trust_tokens/test/trust_token_key_commitment_parser_fuzzer.dict
index c7037fda..a2b8b00 100644
--- a/services/network/trust_tokens/test/trust_token_key_commitment_parser_fuzzer.dict
+++ b/services/network/trust_tokens/test/trust_token_key_commitment_parser_fuzzer.dict
@@ -36,3 +36,7 @@
 "Y"
 "expiry"
 "https"
+"protocol_version"
+"id"
+"unavailable_local_issuance_fallback"
+"request_issuance_locally_on"
diff --git a/services/network/trust_tokens/trust_token_key_commitment_parser.cc b/services/network/trust_tokens/trust_token_key_commitment_parser.cc
index 6fabf7c9..7f4d51bc 100644
--- a/services/network/trust_tokens/trust_token_key_commitment_parser.cc
+++ b/services/network/trust_tokens/trust_token_key_commitment_parser.cc
@@ -7,15 +7,30 @@
 #include "base/base64.h"
 #include "base/json/json_reader.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/values.h"
-#include "services/network/public/mojom/trust_tokens.mojom-forward.h"
 #include "services/network/public/mojom/trust_tokens.mojom.h"
 #include "services/network/trust_tokens/suitable_trust_token_origin.h"
 
 namespace network {
 
+const char kTrustTokenKeyCommitmentProtocolVersionField[] = "protocol_version";
+const char kTrustTokenKeyCommitmentIDField[] = "id";
+const char kTrustTokenKeyCommitmentBatchsizeField[] = "batchsize";
+const char kTrustTokenKeyCommitmentSrrkeyField[] = "srrkey";
+const char kTrustTokenKeyCommitmentExpiryField[] = "expiry";
+const char kTrustTokenKeyCommitmentKeyField[] = "Y";
+const char kTrustTokenKeyCommitmentRequestIssuanceLocallyOnField[] =
+    "request_issuance_locally_on";
+const char kTrustTokenLocalIssuanceOsAndroid[] = "android";
+const char kTrustTokenKeyCommitmentUnavailableLocalIssuanceFallbackField[] =
+    "unavailable_local_issuance_fallback";
+const char kTrustTokenLocalIssuanceFallbackWebIssuance[] = "web_issuance";
+const char kTrustTokenLocalIssuanceFallbackReturnWithError[] =
+    "return_with_error";
+
 namespace {
 
 // Parses a single key label. If |in| is the string representation of an integer
@@ -71,6 +86,82 @@
   return ParseKeyResult::kSucceed;
 }
 
+base::Optional<mojom::TrustTokenKeyCommitmentResult::Os> ParseOs(
+    base::StringPiece os_string) {
+  if (os_string == kTrustTokenLocalIssuanceOsAndroid)
+    return mojom::TrustTokenKeyCommitmentResult::Os::kAndroid;
+  return base::nullopt;
+}
+
+// Attempts to parse a string representation of a member of the
+// UnavailableLocalIssuanceFallback enum, returning true on success and false on
+// failure.
+bool ParseUnavailableLocalIssuanceFallback(
+    base::StringPiece fallback_string,
+    mojom::TrustTokenKeyCommitmentResult::UnavailableLocalIssuanceFallback*
+        fallback_out) {
+  if (fallback_string == kTrustTokenLocalIssuanceFallbackWebIssuance) {
+    *fallback_out = mojom::TrustTokenKeyCommitmentResult::
+        UnavailableLocalIssuanceFallback::kWebIssuance;
+    return true;
+  }
+  if (fallback_string == kTrustTokenLocalIssuanceFallbackReturnWithError) {
+    *fallback_out = mojom::TrustTokenKeyCommitmentResult::
+        UnavailableLocalIssuanceFallback::kReturnWithError;
+    return true;
+  }
+  return false;
+}
+
+// Given a per-issuer key commitment dictionary, looks for the local Trust
+// Tokens issuance-related fields request_issuance_locally_on and
+// unavailable_local_issuance_fallback.
+//
+// Returns true if both are absent, or if both are present and well-formed; in
+// the latter case, updates |result| to with their parsed values. Otherwise,
+// returns false.
+bool ParseLocalIssuanceFieldsIfPresent(
+    const base::Value& value,
+    mojom::TrustTokenKeyCommitmentResult* result) {
+  const base::Value* maybe_request_issuance_locally_on =
+      value.FindKey(kTrustTokenKeyCommitmentRequestIssuanceLocallyOnField);
+
+  // The local issuance field is optional...
+  if (!maybe_request_issuance_locally_on)
+    return true;
+
+  // ...but needs to be the right type if it's provided.
+  if (!maybe_request_issuance_locally_on->is_list())
+    return false;
+
+  for (const base::Value& maybe_os_value :
+       maybe_request_issuance_locally_on->GetList()) {
+    if (!maybe_os_value.is_string())
+      return false;
+    base::Optional<mojom::TrustTokenKeyCommitmentResult::Os> maybe_os =
+        ParseOs(maybe_os_value.GetString());
+    if (!maybe_os)
+      return false;
+    result->request_issuance_locally_on.push_back(*maybe_os);
+  }
+
+  // Deduplicate the OS values:
+  auto& oses = result->request_issuance_locally_on;
+  base::ranges::sort(oses);
+  auto to_remove = base::ranges::unique(oses);
+  oses.erase(to_remove, oses.end());
+
+  const std::string* maybe_fallback = value.FindStringKey(
+      kTrustTokenKeyCommitmentUnavailableLocalIssuanceFallbackField);
+  if (!maybe_fallback ||
+      !ParseUnavailableLocalIssuanceFallback(
+          *maybe_fallback, &result->unavailable_local_issuance_fallback)) {
+    return false;
+  }
+
+  return true;
+}
+
 mojom::TrustTokenKeyCommitmentResultPtr ParseSingleIssuer(
     const base::Value& value) {
   if (!value.is_dict())
@@ -113,6 +204,9 @@
     return nullptr;
   }
 
+  if (!ParseLocalIssuanceFieldsIfPresent(value, result.get()))
+    return nullptr;
+
   // Parse the key commitments in the result (these are exactly the
   // key-value pairs in the dictionary with dictionary-typed values).
   for (const auto& kv : value.DictItems()) {
@@ -155,13 +249,6 @@
 
 }  // namespace
 
-const char kTrustTokenKeyCommitmentProtocolVersionField[] = "protocol_version";
-const char kTrustTokenKeyCommitmentIDField[] = "id";
-const char kTrustTokenKeyCommitmentBatchsizeField[] = "batchsize";
-const char kTrustTokenKeyCommitmentSrrkeyField[] = "srrkey";
-const char kTrustTokenKeyCommitmentExpiryField[] = "expiry";
-const char kTrustTokenKeyCommitmentKeyField[] = "Y";
-
 // https://docs.google.com/document/d/1TNnya6B8pyomDK2F1R9CL3dY10OAmqWlnCxsWyOBDVQ/edit#bookmark=id.6wh9crbxdizi
 // {
 //   "protocol_version" : ..., // Protocol Version; value of type string.
@@ -170,6 +257,12 @@
 //   "srrkey" : ...,           // Required Signed Redemption Record (SRR)
 //                             // verification key, in base64.
 //
+//   // Optional operating systems on which to request issuance via system
+//   // mediation (valid values are: "android"), and (required if at least one
+//   // OS is specified) fallback behavior on other operating systems:
+//   "request_issuance_locally_on": [<os 1>, ..., <os N>],
+//   "unavailable_local_issuance_fallback": "web_issuance" | "return_with_error"
+//
 //   "1" : {                   // Key label, a number in uint32_t range; ignored
 //                             // except for checking that it is present and
 //                             // type-safe.
diff --git a/services/network/trust_tokens/trust_token_key_commitment_parser.h b/services/network/trust_tokens/trust_token_key_commitment_parser.h
index ee12ebb5..52be133 100644
--- a/services/network/trust_tokens/trust_token_key_commitment_parser.h
+++ b/services/network/trust_tokens/trust_token_key_commitment_parser.h
@@ -14,41 +14,48 @@
 
 namespace network {
 
-// Field names from the key commitment JSON format specified in the Trust Tokens
-// design doc
-// (https://docs.google.com/document/d/1TNnya6B8pyomDK2F1R9CL3dY10OAmqWlnCxsWyOBDVQ/edit#bookmark=id.6wh9crbxdizi):
-// - "protocol_version" (version of Trust Token used for this commitment)
+// These field names are from the key commitment JSON format specified in the
+// Trust Tokens design doc
+// (https://docs.google.com/document/d/1TNnya6B8pyomDK2F1R9CL3dY10OAmqWlnCxsWyOBDVQ/edit#bookmark=id.6wh9crbxdizi).
+// "protocol version" (version of Trust Token used for this commitment):
 extern const char kTrustTokenKeyCommitmentProtocolVersionField[];
-// - "id" (ID for this key commitment)
+// This commitment's ID, used for mediating between concurrencyID for this key
+// commitment):
 extern const char kTrustTokenKeyCommitmentIDField[];
-// - "batch size" (number of blinded tokens to provide per issuance request)
+// "Batch size" (number of blinded tokens to provide per issuance request):
 extern const char kTrustTokenKeyCommitmentBatchsizeField[];
-// - verification key for the signatures the issuer provides over its Signed
-// Redemption Records (SRRs)
+// Verification key for the signatures the issuer provides over its Signed
+// Redemption Records (SRRs):
 extern const char kTrustTokenKeyCommitmentSrrkeyField[];
-// - each issuance key's expiry timestamp
+// Each issuance key's expiry timestamp:
 extern const char kTrustTokenKeyCommitmentExpiryField[];
-// - each issuance key's key material
+// Each issuance key's key material:
 extern const char kTrustTokenKeyCommitmentKeyField[];
 
+// The operating systems on which to request issuance via system mediation
+// rather than through a request to the issuer's website:
+extern const char kTrustTokenKeyCommitmentRequestIssuanceLocallyOnField[];
+extern const char kTrustTokenKeyCommitmentOsAndroid[];
+
+// The desired fallback behavior when local issuance isn't available on the
+// requested operating system:
+extern const char
+    kTrustTokenKeyCommitmentUnavailableLocalIssuanceFallbackField[];
+extern const char kTrustTokenLocalIssuanceFallbackWebIssuance[];
+extern const char kTrustTokenLocalIssuanceFallbackReturnWithError[];
+
 class TrustTokenKeyCommitmentParser
     : public TrustTokenKeyCommitmentController::Parser {
  public:
   TrustTokenKeyCommitmentParser() = default;
   ~TrustTokenKeyCommitmentParser() override = default;
 
-  // Parses a JSON key commitment response.
+  // Parses a JSON key commitment response, returning nullptr if the input is
+  // not a valid representation of a JSON dictionary containing all required
+  // fields listed in the Trust Tokens design doc, the current normative source
+  // for key commitment responses' format:
   //
-  // This method returns nullptr unless:
-  // - the input is valid JSON; and
-  // - the JSON represents a nonempty dictionary; and
-  // - within this inner dictionary (which stores metadata like batch size, as
-  // well as more dictionaries denoting keys' information):
-  //   - every dictionary-type value has an expiry field
-  //   (|kTrustTokenKeyCommitmentExpiryField| above) and a key body field
-  //   (|kTrustTokenKeyCommitmentKeyField|), and
-  //   - the expiry field is a positive integer (microseconds since the Unix
-  //   epoch) storing a time in the future.
+  // https://docs.google.com/document/d/1TNnya6B8pyomDK2F1R9CL3dY10OAmqWlnCxsWyOBDVQ/edit#heading=h.wkezf6pcskvh
   mojom::TrustTokenKeyCommitmentResultPtr Parse(
       base::StringPiece response_body) override;
 
diff --git a/services/network/trust_tokens/trust_token_key_commitment_parser_unittest.cc b/services/network/trust_tokens/trust_token_key_commitment_parser_unittest.cc
index ce49d8a..1040d8b 100644
--- a/services/network/trust_tokens/trust_token_key_commitment_parser_unittest.cc
+++ b/services/network/trust_tokens/trust_token_key_commitment_parser_unittest.cc
@@ -429,6 +429,8 @@
      "protocol_version": "TrustTokenV1", "id": 1, "batchsize": 5,
      "srrkey": "aaaa"
    })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
 
   mojom::TrustTokenKeyCommitmentResultPtr result =
       TrustTokenKeyCommitmentParser().Parse(input);
@@ -440,8 +442,10 @@
 TEST(TrustTokenKeyCommitmentParser, RejectsMissingBatchSize) {
   std::string input =
       R"({
-     "protocol_version": "TrustTokenV1", "id": 1, "srrkey": "aaaa",
+     "protocol_version": "TrustTokenV1", "id": 1, "srrkey": "aaaa"
    })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
 
   mojom::TrustTokenKeyCommitmentResultPtr result =
       TrustTokenKeyCommitmentParser().Parse(input);
@@ -452,8 +456,10 @@
   std::string input =
       R"({
      "protocol_version": "TrustTokenV1", "id": 1, "srrkey": "aaaa",
-     "batchsize": "0",
+     "batchsize": 0
    })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
 
   mojom::TrustTokenKeyCommitmentResultPtr result =
       TrustTokenKeyCommitmentParser().Parse(input);
@@ -466,18 +472,234 @@
      "protocol_version": "TrustTokenV1", "id": 1, "srrkey": "aaaa",
      "batchsize": "not a number"
    })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
 
   mojom::TrustTokenKeyCommitmentResultPtr result =
       TrustTokenKeyCommitmentParser().Parse(input);
   EXPECT_FALSE(result);
 }
 
+TEST(TrustTokenKeyCommitmentParser, RequestIssuanceLocallyOn) {
+  std::string input =
+      R"({
+     "srrkey": "aaaa",
+     "batchsize": 1,
+     "protocol_version": "TrustTokenV1",
+     "id": 1,
+     "request_issuance_locally_on": ["android"],
+     "unavailable_local_issuance_fallback": "web_issuance"
+   })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
+
+  mojom::TrustTokenKeyCommitmentResultPtr result =
+      TrustTokenKeyCommitmentParser().Parse(input);
+  ASSERT_TRUE(result);
+  EXPECT_THAT(result->request_issuance_locally_on,
+              ElementsAre(mojom::TrustTokenKeyCommitmentResult::Os::kAndroid));
+}
+
+TEST(TrustTokenKeyCommitmentParser, DeduplicatesRequestIssuanceLocallyOn) {
+  std::string input =
+      R"({
+     "srrkey": "aaaa",
+     "batchsize": 1,
+     "protocol_version": "TrustTokenV1",
+     "id": 1,
+     "request_issuance_locally_on": ["android", "android", "android"],
+     "unavailable_local_issuance_fallback": "web_issuance"
+   })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
+
+  mojom::TrustTokenKeyCommitmentResultPtr result =
+      TrustTokenKeyCommitmentParser().Parse(input);
+  ASSERT_TRUE(result);
+  EXPECT_THAT(result->request_issuance_locally_on,
+              ElementsAre(mojom::TrustTokenKeyCommitmentResult::Os::kAndroid));
+}
+
+TEST(TrustTokenKeyCommitmentParser, NoRequestIssuanceLocallyOn) {
+  std::string input =
+      R"({
+     "srrkey": "aaaa",
+     "batchsize": 1,
+     "protocol_version": "TrustTokenV1",
+     "id": 1
+   })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
+
+  mojom::TrustTokenKeyCommitmentResultPtr result =
+      TrustTokenKeyCommitmentParser().Parse(input);
+  ASSERT_TRUE(result);
+  EXPECT_TRUE(result->request_issuance_locally_on.empty());
+}
+
+TEST(TrustTokenKeyCommitmentParser, RejectsTypeUnsafeRequestIssuanceLocallyOn) {
+  std::string input =
+      R"({
+     "srrkey": "aaaa",
+     "batchsize": 1,
+     "protocol_version": "TrustTokenV1",
+     "id": 1,
+     "request_issuance_locally_on": "not an array",
+     "unavailable_local_issuance_fallback": "web_issuance"
+   })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
+
+  mojom::TrustTokenKeyCommitmentResultPtr result =
+      TrustTokenKeyCommitmentParser().Parse(input);
+  EXPECT_FALSE(result);
+}
+
+TEST(TrustTokenKeyCommitmentParser,
+     RejectsTypeUnsafeRequestIssuanceLocallyOnMember) {
+  std::string input =
+      R"({
+     "srrkey": "aaaa",
+     "batchsize": 1,
+     "protocol_version": "TrustTokenV1",
+     "id": 1,
+     "request_issuance_locally_on": ["android", 47],
+     "unavailable_local_issuance_fallback": "web_issuance"
+   })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
+
+  mojom::TrustTokenKeyCommitmentResultPtr result =
+      TrustTokenKeyCommitmentParser().Parse(input);
+  EXPECT_FALSE(result);
+}
+
+TEST(TrustTokenKeyCommitmentParser,
+     RejectsUnrecognizedOsInRequestIssuanceLocallyOn) {
+  std::string input =
+      R"({
+     "srrkey": "aaaa",
+     "batchsize": 1,
+     "protocol_version": "TrustTokenV1",
+     "id": 1,
+     "request_issuance_locally_on": ["android", "imaginaryOS"],
+     "unavailable_local_issuance_fallback": "web_issuance"
+   })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
+
+  mojom::TrustTokenKeyCommitmentResultPtr result =
+      TrustTokenKeyCommitmentParser().Parse(input);
+  EXPECT_FALSE(result);
+}
+
+TEST(TrustTokenKeyCommitmentParser,
+     ProvidingLocalIssuanceOsRequiresSpecifyingIssuanceFallback) {
+  std::string input =
+      R"({
+     "srrkey": "aaaa",
+     "batchsize": 1,
+     "protocol_version": "TrustTokenV1",
+     "id": 1,
+     "request_issuance_locally_on": ["android"]
+   })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
+
+  mojom::TrustTokenKeyCommitmentResultPtr result =
+      TrustTokenKeyCommitmentParser().Parse(input);
+  EXPECT_FALSE(result);
+}
+
+TEST(TrustTokenKeyCommitmentParser,
+     RejectsTypeUnsafeUnavailableLocalIssuanceFallback) {
+  std::string input =
+      R"({
+     "srrkey": "aaaa",
+     "batchsize": 1,
+     "protocol_version": "TrustTokenV1",
+     "id": 1,
+     "request_issuance_locally_on": ["android"],
+     "unavailable_local_issuance_fallback": 57
+   })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
+
+  mojom::TrustTokenKeyCommitmentResultPtr result =
+      TrustTokenKeyCommitmentParser().Parse(input);
+  EXPECT_FALSE(result);
+}
+
+TEST(TrustTokenKeyCommitmentParser,
+     RejectsUnrecognizedUnavailableLocalIssuanceFallback) {
+  std::string input =
+      R"({
+     "srrkey": "aaaa",
+     "batchsize": 1,
+     "protocol_version": "TrustTokenV1",
+     "id": 1,
+     "request_issuance_locally_on": ["android"],
+     "unavailable_local_issuance_fallback": "not a valid enum value"
+   })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
+
+  mojom::TrustTokenKeyCommitmentResultPtr result =
+      TrustTokenKeyCommitmentParser().Parse(input);
+  EXPECT_FALSE(result);
+}
+
+TEST(TrustTokenKeyCommitmentParser, ParsesLocalIssuanceFallbackWebIssuance) {
+  std::string input =
+      R"({
+     "srrkey": "aaaa",
+     "batchsize": 1,
+     "protocol_version": "TrustTokenV1",
+     "id": 1,
+     "request_issuance_locally_on": ["android"],
+     "unavailable_local_issuance_fallback": "web_issuance"
+   })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
+
+  mojom::TrustTokenKeyCommitmentResultPtr result =
+      TrustTokenKeyCommitmentParser().Parse(input);
+  ASSERT_TRUE(result);
+  EXPECT_EQ(result->unavailable_local_issuance_fallback,
+            mojom::TrustTokenKeyCommitmentResult::
+                UnavailableLocalIssuanceFallback::kWebIssuance);
+}
+
+TEST(TrustTokenKeyCommitmentParser,
+     ParsesLocalIssuanceFallbackReturnWithError) {
+  std::string input =
+      R"({
+     "srrkey": "aaaa",
+     "batchsize": 1,
+     "protocol_version": "TrustTokenV1",
+     "id": 1,
+     "request_issuance_locally_on": ["android"],
+     "unavailable_local_issuance_fallback": "return_with_error"
+   })";
+  // Double-check that the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
+
+  mojom::TrustTokenKeyCommitmentResultPtr result =
+      TrustTokenKeyCommitmentParser().Parse(input);
+  ASSERT_TRUE(result);
+  EXPECT_EQ(result->unavailable_local_issuance_fallback,
+            mojom::TrustTokenKeyCommitmentResult::
+                UnavailableLocalIssuanceFallback::kReturnWithError);
+}
+
 TEST(TrustTokenKeyCommitmentParser, ParsesProtocolVersion) {
   std::string input =
       R"({
      "protocol_version": "TrustTokenV1", "id": 1, "batchsize": 5,
      "srrkey": "aaaa"
    })";
+  // Make sure the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
 
   mojom::TrustTokenKeyCommitmentResultPtr result =
       TrustTokenKeyCommitmentParser().Parse(input);
@@ -489,8 +711,10 @@
 TEST(TrustTokenKeyCommitmentParser, RejectsMissingProtocolVersion) {
   std::string input =
       R"({
-     "id": 1, "batchsize": 5, "srrkey": "aaaa",
+     "id": 1, "batchsize": 5, "srrkey": "aaaa"
    })";
+  // Make sure the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
 
   mojom::TrustTokenKeyCommitmentResultPtr result =
       TrustTokenKeyCommitmentParser().Parse(input);
@@ -503,6 +727,8 @@
      "protocol_version": "TrustTokenJunk", "id": 1, "srrkey": "aaaa",
      "batchsize": 5
    })";
+  // Make sure the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
 
   mojom::TrustTokenKeyCommitmentResultPtr result =
       TrustTokenKeyCommitmentParser().Parse(input);
@@ -515,6 +741,8 @@
      "protocol_version": 5, "id": 1, "srrkey": "aaaa",
      "batchsize": 5
    })";
+  // Make sure the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
 
   mojom::TrustTokenKeyCommitmentResultPtr result =
       TrustTokenKeyCommitmentParser().Parse(input);
@@ -527,6 +755,8 @@
      "protocol_version": "TrustTokenV1", "id": 1, "batchsize": 5,
      "srrkey": "aaaa"
    })";
+  // Make sure the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
 
   mojom::TrustTokenKeyCommitmentResultPtr result =
       TrustTokenKeyCommitmentParser().Parse(input);
@@ -538,8 +768,10 @@
 TEST(TrustTokenKeyCommitmentParser, RejectsMissingID) {
   std::string input =
       R"({
-     "protocol_version": "TrustTokenV1", "batchsize": 5, "srrkey": "aaaa",
+     "protocol_version": "TrustTokenV1", "batchsize": 5, "srrkey": "aaaa"
    })";
+  // Make sure the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
 
   mojom::TrustTokenKeyCommitmentResultPtr result =
       TrustTokenKeyCommitmentParser().Parse(input);
@@ -552,6 +784,8 @@
      "protocol_version": "TrustTokenV1", "id": "foo", "srrkey": "aaaa",
      "batchsize": 5
    })";
+  // Make sure the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
 
   mojom::TrustTokenKeyCommitmentResultPtr result =
       TrustTokenKeyCommitmentParser().Parse(input);
@@ -569,6 +803,8 @@
 
 TEST(TrustTokenKeyCommitmentParserMultipleIssuers, NotADictionary) {
   std::string input = "3";
+  // Make sure the input is actually valid JSON.
+  ASSERT_TRUE(base::JSONReader::Read(input));
 
   auto result = TrustTokenKeyCommitmentParser().ParseMultipleIssuers(input);
   EXPECT_FALSE(result);
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index e4d45627..05a9010 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -6721,7 +6721,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Windows-10-18363",
+              "os": "Windows-10-15063",
               "pool": "chrome.tests"
             }
           ],
@@ -6747,7 +6747,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Windows-10-18363",
+              "os": "Windows-10-15063",
               "pool": "chrome.tests"
             }
           ],
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index b13baba9..810bc5a0 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -3014,7 +3014,7 @@
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
+          "shards": 4
         },
         "test_id_prefix": "ninja://third_party/angle/src/tests:angle_perftests/"
       }
diff --git a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter
index 9521787..604e196 100644
--- a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter
+++ b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter
@@ -96,6 +96,8 @@
 -OobeTest.*
 -OobeZeroTouchInteractiveUITest.*
 -PackagedLicenseScreenTest.*
+-ParentalHandoffScreenBrowserTest.*
+-ParentalHandoffScreenChildBrowserTest.*
 -PolicyProvidedCertsOnUserSessionInitTest.*
 -PresetPolicyDeviceDisablingTest.*
 -PrimaryUserPoliciesProxiedTest.*
diff --git a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter
index 9d978c3..4ed8b56 100644
--- a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter
+++ b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter
@@ -96,6 +96,8 @@
 OobeTest.*
 OobeZeroTouchInteractiveUITest.*
 PackagedLicenseScreenTest.*
+ParentalHandoffScreenBrowserTest.*
+ParentalHandoffScreenChildBrowserTest.*
 PolicyProvidedCertsOnUserSessionInitTest.*
 PresetPolicyDeviceDisablingTest.*
 PrimaryUserPoliciesProxiedTest.*
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 35496c1b..faf2ba7 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -75,6 +75,13 @@
     },
   },
   'angle_perftests': {
+    'modifications': {
+     'Android FYI 64 Perf (Pixel 2)': { # crbug.com/1140626
+       'swarming': {
+         'shards': 4,
+       },
+     },
+    },
     'remove_from': [
       'Android FYI Release (Nexus 5)',  # crbug.com/915429
       'Android FYI Release (Nexus 6)',  # anglebug.com/2433
@@ -856,6 +863,32 @@
       }
     }
   },
+  'chrome_sizes': {
+    'modifications': {
+      'win-chrome': {
+        'swarming': {
+          # TODO(crbug.com/1124829): Remove this exception once pool
+          # chrome.tests is migrated to 1909.
+          'dimension_sets': [
+            {
+              'os': 'Windows-10-15063',
+            },
+          ],
+        },
+      },
+      'win64-chrome': {
+        'swarming': {
+          # TODO(crbug.com/1124829): Remove this exception once pool
+          # chrome.tests is migrated to 1909.
+          'dimension_sets': [
+            {
+              'os': 'Windows-10-15063',
+            },
+          ],
+        },
+      },
+    },
+  },
   'chromedriver_py_tests': {
     'remove_from': [
       # Timeout happens sometimes (crbug.com/951799).
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 32dc40a9..edcdbf3 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2839,12 +2839,10 @@
         'use_swarming': False,
       },
       'win10-blink-rel-dummy': {
+        'mixins': [
+            'win10',
+        ],
         'swarming': {
-          'dimension_sets': [
-            {
-              'os': 'Windows-10-15063',
-            },
-          ],
           'hard_timeout': 900,
         },
         'test_suites': {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 089a523..fd01e94a8 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -6894,8 +6894,7 @@
                 {
                     "name": "Enabled",
                     "enable_features": [
-                        "TabSearch",
-                        "TabSearchFixedEntrypoint"
+                        "TabSearch"
                     ]
                 }
             ]
@@ -7836,6 +7835,24 @@
             ]
         }
     ],
+    "WebRTC-VP8-Postproc-Config": [
+        {
+            "platforms": [
+                "windows",
+                "mac",
+                "chromeos",
+                "linux",
+                "android",
+                "android_weblayer",
+                "android_webview"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled-8,30,60"
+                }
+            ]
+        }
+    ],
     "WebRTC-VP8ConferenceTemporalLayers": [
         {
             "platforms": [
diff --git a/third_party/accessibility_test_framework/BUILD.gn b/third_party/accessibility_test_framework/BUILD.gn
index 3cddc14..b4bd2f3 100644
--- a/third_party/accessibility_test_framework/BUILD.gn
+++ b/third_party/accessibility_test_framework/BUILD.gn
@@ -10,6 +10,7 @@
   # Uses wrong version of proto (not protolite).
   # Disable these to avoid build warnings.
   enable_bytecode_checks = false
+  enable_desugar = false
 
   jar_path = "lib/accessibility-test-framework.jar"
   deps = [
diff --git a/third_party/blink/public/web/blink.h b/third_party/blink/public/web/blink.h
index 00de4f8..c2bcb0b 100644
--- a/third_party/blink/public/web/blink.h
+++ b/third_party/blink/public/web/blink.h
@@ -112,6 +112,7 @@
 // agents, not both.
 // This is called at most once. This is called earlier than any frame commit.
 BLINK_EXPORT void SetIsCrossOriginIsolated(bool value);
+BLINK_EXPORT bool IsCrossOriginIsolated();
 
 }  // namespace blink
 
diff --git a/third_party/blink/public/web/web_frame_widget.h b/third_party/blink/public/web/web_frame_widget.h
index 445132b..e5e47ed 100644
--- a/third_party/blink/public/web/web_frame_widget.h
+++ b/third_party/blink/public/web/web_frame_widget.h
@@ -184,9 +184,6 @@
   // If the widget is currently selecting a range.
   virtual bool HandlingSelectRange() = 0;
 
-  // If fullscreen has been granted.
-  virtual bool IsFullscreenGranted() = 0;
-
   // Returns true if a pinch gesture is currently active in main frame.
   virtual bool PinchGestureActiveInMainFrame() = 0;
 
diff --git a/third_party/blink/renderer/bindings/core/v8/custom/v8_window_custom.cc b/third_party/blink/renderer/bindings/core/v8/custom/v8_window_custom.cc
index 73980312..d5bb02025 100644
--- a/third_party/blink/renderer/bindings/core/v8/custom/v8_window_custom.cc
+++ b/third_party/blink/renderer/bindings/core/v8/custom/v8_window_custom.cc
@@ -86,7 +86,8 @@
     DOMWrapperWorld& world = DOMWrapperWorld::Current(isolate);
     const auto* location_wrapper_type = location->GetWrapperTypeInfo();
     v8::Local<v8::Object> new_wrapper =
-        location_wrapper_type->DomTemplate(isolate, world)
+        location_wrapper_type->GetV8ClassTemplate(isolate, world)
+            .As<v8::FunctionTemplate>()
             ->NewRemoteInstance()
             .ToLocalChecked();
 
diff --git a/third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.cc b/third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.cc
index 3a4ba8e..113918f 100644
--- a/third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.cc
+++ b/third_party/blink/renderer/bindings/core/v8/custom_wrappable_adapter.cc
@@ -13,36 +13,29 @@
 
 namespace {
 
-v8::Local<v8::FunctionTemplate> CreateCustomWrappableTemplate(
-    v8::Isolate* isolate,
-    const DOMWrapperWorld& world);
+void InstallCustomWrappableTemplate(v8::Isolate* isolate,
+                                    const DOMWrapperWorld& world,
+                                    v8::Local<v8::Template> v8_template);
 
 const WrapperTypeInfo custom_wrappable_info = {
     gin::kEmbedderBlink,
-    CreateCustomWrappableTemplate,
+    InstallCustomWrappableTemplate,
     nullptr,
     "CustomWrappableAdapter",
     nullptr,
     WrapperTypeInfo::kWrapperTypeNoPrototype,
     WrapperTypeInfo::kCustomWrappableId,
     WrapperTypeInfo::kNotInheritFromActiveScriptWrappable,
+    WrapperTypeInfo::kCustomWrappableKind,
 };
 
-void InstallCustomWrappableTemplate(
-    v8::Isolate* isolate,
-    const DOMWrapperWorld& world,
-    v8::Local<v8::FunctionTemplate> interfaceTemplate) {
+void InstallCustomWrappableTemplate(v8::Isolate* isolate,
+                                    const DOMWrapperWorld& world,
+                                    v8::Local<v8::Template> v8_template) {
   V8DOMConfiguration::InitializeDOMInterfaceTemplate(
-      isolate, interfaceTemplate, custom_wrappable_info.interface_name,
-      v8::Local<v8::FunctionTemplate>(), kV8DefaultWrapperInternalFieldCount);
-}
-
-v8::Local<v8::FunctionTemplate> CreateCustomWrappableTemplate(
-    v8::Isolate* isolate,
-    const DOMWrapperWorld& world) {
-  return V8DOMConfiguration::DomClassTemplate(
-      isolate, world, const_cast<WrapperTypeInfo*>(&custom_wrappable_info),
-      InstallCustomWrappableTemplate);
+      isolate, v8_template.As<v8::FunctionTemplate>(),
+      custom_wrappable_info.interface_name, v8::Local<v8::FunctionTemplate>(),
+      kV8DefaultWrapperInternalFieldCount);
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
index 55b52457..7d338b7a 100644
--- a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
+++ b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
@@ -160,6 +160,44 @@
 
 namespace bindings {
 
+void SetupIDLInterfaceTemplates(
+    v8::Isolate* isolate,
+    const WrapperTypeInfo* wrapper_type_info,
+    v8::Local<v8::ObjectTemplate> instance_template,
+    v8::Local<v8::ObjectTemplate> prototype_template,
+    v8::Local<v8::FunctionTemplate> interface_template,
+    v8::Local<v8::FunctionTemplate> parent_interface_template) {
+  v8::Local<v8::String> class_string =
+      V8AtomicString(isolate, wrapper_type_info->interface_name);
+
+  if (!parent_interface_template.IsEmpty())
+    interface_template->Inherit(parent_interface_template);
+  interface_template->ReadOnlyPrototype();
+  interface_template->SetClassName(class_string);
+
+  prototype_template->Set(
+      v8::Symbol::GetToStringTag(isolate), class_string,
+      static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum));
+
+  instance_template->SetInternalFieldCount(kV8DefaultWrapperInternalFieldCount);
+}
+
+void SetupIDLNamespaceTemplate(
+    v8::Isolate* isolate,
+    const WrapperTypeInfo* wrapper_type_info,
+    v8::Local<v8::ObjectTemplate> interface_template) {
+  // TODO(yukishiino): To be implemented.
+}
+
+void SetupIDLCallbackInterfaceTemplate(
+    v8::Isolate* isolate,
+    const WrapperTypeInfo* wrapper_type_info,
+    v8::Local<v8::FunctionTemplate> interface_template) {
+  interface_template->RemovePrototype();
+  interface_template->SetClassName(
+      V8AtomicString(isolate, wrapper_type_info->interface_name));
+}
+
 base::Optional<size_t> FindIndexInEnumStringTable(
     v8::Isolate* isolate,
     v8::Local<v8::Value> value,
@@ -278,7 +316,8 @@
         func_length, v8::ConstructorBehavior::kAllow,
         v8::SideEffectType::kHasSideEffect);
     v8::Local<v8::FunctionTemplate> interface_template =
-        wrapper_type_info->DomTemplate(isolate, world);
+        wrapper_type_info->GetV8ClassTemplate(isolate, world)
+            .As<v8::FunctionTemplate>();
     function_template->Inherit(interface_template);
     function_template->SetClassName(V8AtomicString(isolate, func_name));
     function_template->InstanceTemplate()->SetInternalFieldCount(
@@ -352,9 +391,9 @@
 void InstallCSSPropertyAttributes(
     v8::Isolate* isolate,
     const DOMWrapperWorld& world,
-    v8::Local<v8::ObjectTemplate> instance_template,
-    v8::Local<v8::ObjectTemplate> prototype_template,
-    v8::Local<v8::FunctionTemplate> interface_template,
+    v8::Local<v8::Template> instance_template,
+    v8::Local<v8::Template> prototype_template,
+    v8::Local<v8::Template> interface_template,
     v8::Local<v8::Signature> signature,
     base::span<const char* const> css_property_names) {
   const String kGetPrefix = "get ";
diff --git a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
index 44a3136..7209816 100644
--- a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
+++ b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
@@ -99,6 +99,24 @@
 
 namespace bindings {
 
+CORE_EXPORT void SetupIDLInterfaceTemplates(
+    v8::Isolate* isolate,
+    const WrapperTypeInfo* wrapper_type_info,
+    v8::Local<v8::ObjectTemplate> instance_template,
+    v8::Local<v8::ObjectTemplate> prototype_template,
+    v8::Local<v8::FunctionTemplate> interface_template,
+    v8::Local<v8::FunctionTemplate> parent_interface_template);
+
+CORE_EXPORT void SetupIDLNamespaceTemplate(
+    v8::Isolate* isolate,
+    const WrapperTypeInfo* wrapper_type_info,
+    v8::Local<v8::ObjectTemplate> interface_template);
+
+CORE_EXPORT void SetupIDLCallbackInterfaceTemplate(
+    v8::Isolate* isolate,
+    const WrapperTypeInfo* wrapper_type_info,
+    v8::Local<v8::FunctionTemplate> interface_template);
+
 // Returns the length of arguments ignoring the undefined values at the end.
 inline int NonUndefinedArgumentLength(
     const v8::FunctionCallbackInfo<v8::Value>& info) {
@@ -232,9 +250,9 @@
 CORE_EXPORT void InstallCSSPropertyAttributes(
     v8::Isolate* isolate,
     const DOMWrapperWorld& world,
-    v8::Local<v8::ObjectTemplate> instance_template,
-    v8::Local<v8::ObjectTemplate> prototype_template,
-    v8::Local<v8::FunctionTemplate> interface_template,
+    v8::Local<v8::Template> instance_template,
+    v8::Local<v8::Template> prototype_template,
+    v8::Local<v8::Template> interface_template,
     v8::Local<v8::Signature> signature,
     base::span<const char* const> css_property_names);
 CORE_EXPORT void CSSPropertyAttributeGet(
diff --git a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
index be4c805..16d2cc4 100644
--- a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
+++ b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
@@ -235,7 +235,10 @@
     // in some cases, e.g. loading XML files.
     if (context.IsEmpty()) {
       v8::Local<v8::ObjectTemplate> global_template =
-          V8Window::DomTemplate(isolate, World())->InstanceTemplate();
+          V8Window::GetWrapperTypeInfo()
+              ->GetV8ClassTemplate(isolate, World())
+              .As<v8::FunctionTemplate>()
+              ->InstanceTemplate();
       CHECK(!global_template.IsEmpty());
       context = v8::Context::New(isolate, &extension_configuration,
                                  global_template, global_proxy);
diff --git a/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc
index 0b79324d..ab2c20f 100644
--- a/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc
+++ b/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc
@@ -106,7 +106,10 @@
   // Create a new v8::Context with the window object as the global object
   // (aka the inner global). Reuse the outer global proxy if it already exists.
   v8::Local<v8::ObjectTemplate> global_template =
-      V8Window::DomTemplate(GetIsolate(), *world_)->InstanceTemplate();
+      V8Window::GetWrapperTypeInfo()
+          ->GetV8ClassTemplate(GetIsolate(), *world_)
+          .As<v8::FunctionTemplate>()
+          ->InstanceTemplate();
   CHECK(!global_template.IsEmpty());
 
   v8::Local<v8::Object> global_proxy =
diff --git a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
index 41f6319..4f3b691b 100644
--- a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
+++ b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
@@ -134,7 +134,8 @@
   const WrapperTypeInfo* wrapper_type_info =
       script_wrappable->GetWrapperTypeInfo();
   v8::Local<v8::FunctionTemplate> global_interface_template =
-      wrapper_type_info->DomTemplate(isolate_, *world_);
+      wrapper_type_info->GetV8ClassTemplate(isolate_, *world_)
+          .As<v8::FunctionTemplate>();
   DCHECK(!global_interface_template.IsEmpty());
   v8::Local<v8::ObjectTemplate> global_template =
       global_interface_template->InstanceTemplate();
diff --git a/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc b/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc
index 68e739a..4985457 100644
--- a/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc
+++ b/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc
@@ -109,14 +109,14 @@
              const DOMWrapperWorld& world,
              v8::Local<v8::Object> instance_object,
              v8::Local<v8::Object> prototype_object,
-             v8::Local<v8::Function> interface_object,
-             v8::Local<v8::FunctionTemplate> interface_template);
+             v8::Local<v8::Object> interface_object,
+             v8::Local<v8::Template> interface_template);
 using InstallPropsPerIsolate =
     void (*)(v8::Isolate* isolate,
              const DOMWrapperWorld& world,
-             v8::Local<v8::ObjectTemplate> instance_template,
-             v8::Local<v8::ObjectTemplate> prototype_template,
-             v8::Local<v8::FunctionTemplate> interface_template);
+             v8::Local<v8::Template> instance_template,
+             v8::Local<v8::Template> prototype_template,
+             v8::Local<v8::Template> interface_template);
 
 // Construction of |type_info_table| requires non-trivial initialization due
 // to cross-component address resolution.  We ignore this issue because the
@@ -292,7 +292,9 @@
 
   // Set up the context and global object.
   v8::Local<v8::FunctionTemplate> window_interface_template =
-      V8Window::GetWrapperTypeInfo()->DomTemplate(isolate, world);
+      V8Window::GetWrapperTypeInfo()
+          ->GetV8ClassTemplate(isolate, world)
+          .As<v8::FunctionTemplate>();
   v8::Local<v8::ObjectTemplate> window_instance_template =
       window_interface_template->InstanceTemplate();
   v8::Local<v8::Context> context;
@@ -325,7 +327,7 @@
   snapshot_creator->AddContext(context, SerializeInternalFieldCallback);
   for (const auto& type_info : type_info_table) {
     snapshot_creator->AddData(
-        type_info.wrapper_type_info->DomTemplate(isolate, world));
+        type_info.wrapper_type_info->GetV8ClassTemplate(isolate, world));
   }
 }
 
@@ -380,8 +382,8 @@
       continue;
 
     const auto* wrapper_type_info = type_info.wrapper_type_info;
-    v8::Local<v8::FunctionTemplate> interface_template =
-        wrapper_type_info->DomTemplate(isolate, world);
+    v8::Local<v8::Template> interface_template =
+        wrapper_type_info->GetV8ClassTemplate(isolate, world);
     v8::Local<v8::Function> interface_object =
         per_context_data->ConstructorForType(wrapper_type_info);
     v8::Local<v8::Object> prototype_object =
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/callback_interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/callback_interface.py
index 7d8cea4..31793e5 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/callback_interface.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/callback_interface.py
@@ -202,7 +202,6 @@
     ])
     installer_function_defs.accumulate(
         CodeGenAccumulator.require_include_headers([
-            "third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.h",
             "third_party/blink/renderer/platform/bindings/idl_member_installer.h",
         ]))
 
@@ -311,13 +310,6 @@
 
         class_def.public_section.append(get_wrapper_type_info_def)
         class_def.public_section.append(EmptyNode())
-        class_def.public_section.extend([
-            TextNode("// Migration adapter"),
-            TextNode("static v8::Local<v8::FunctionTemplate> DomTemplate("
-                     "v8::Isolate* isolate, "
-                     "const DOMWrapperWorld& world);"),
-            EmptyNode(),
-        ])
         class_def.private_section.append(wrapper_type_info_var_def)
         class_def.private_section.append(EmptyNode())
         source_blink_ns.body.extend([
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
index cda3024..8a0b7c7 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -2652,6 +2652,10 @@
     bindings::EnumerateIndexedProperties(${isolate}, length);
 bindings::V8SetReturnValue(${info}, array);
 """))
+    body.accumulate(
+        CodeGenAccumulator.require_include_headers([
+            "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h"
+        ]))
 
     return func_decl, func_def
 
@@ -4175,29 +4179,60 @@
     local_vars = []
 
     local_vars.extend([
-        S("instance_template",
-          ("v8::Local<v8::ObjectTemplate> ${instance_template} = "
-           "${interface_template}->InstanceTemplate();")),
-        S("interface_template",
-          ("v8::Local<v8::FunctionTemplate> ${interface_template} = "
-           "${wrapper_type_info}->DomTemplate(${isolate}, ${world});")),
         S("is_in_secure_context",
           ("const bool ${is_in_secure_context} = "
            "${execution_context}->IsSecureContext();")),
         S("isolate", "v8::Isolate* ${isolate} = ${v8_context}->GetIsolate();"),
-        S("prototype_template",
-          ("v8::Local<v8::ObjectTemplate> ${prototype_template} = "
-           "${interface_template}->PrototypeTemplate();")),
         S("script_state",
           "ScriptState* ${script_state} = ScriptState::From(${v8_context});"),
-        S("signature",
-          ("v8::Local<v8::Signature> ${signature} = "
-           "v8::Signature::New(${isolate}, ${interface_template});")),
         S("wrapper_type_info",
           ("const WrapperTypeInfo* const ${wrapper_type_info} = "
            "${class_name}::GetWrapperTypeInfo();")),
     ])
 
+    if cg_context.interface:
+        local_vars.extend([
+            S("interface_function_template",
+              ("v8::Local<v8::FunctionTemplate> "
+               "${interface_function_template} = "
+               "${interface_template}.As<v8::FunctionTemplate>();")),
+            S("instance_object_template",
+              ("v8::Local<v8::ObjectTemplate> ${instance_object_template} = "
+               "${interface_function_template}->InstanceTemplate();")),
+            S("instance_template",
+              ("v8::Local<v8::Template> ${instance_template} = "
+               "${instance_object_template};")),
+            S("prototype_object_template",
+              ("v8::Local<v8::ObjectTemplate> ${prototype_object_template} = "
+               "${interface_function_template}->PrototypeTemplate();")),
+            S("prototype_template",
+              ("v8::Local<v8::Template> ${prototype_template} = "
+               "${prototype_object_template};")),
+            S("signature", ("v8::Local<v8::Signature> ${signature} = "
+                            "v8::Signature::New(${isolate}, "
+                            "${interface_function_template});")),
+        ])
+    elif cg_context.namespace:
+        local_vars.extend([
+            S("instance_template",
+              "v8::Local<v8::Template> ${instance_template};"),
+            S("prototype_template",
+              "v8::Local<v8::Template> ${prototype_template};"),
+            S("signature", "v8::Local<v8::Signature> ${signature};"),
+        ])
+    elif cg_context.callback_interface:
+        local_vars.extend([
+            S("interface_function_template",
+              ("v8::Local<v8::FunctionTemplate> "
+               "${interface_function_template} = "
+               "${interface_template}.As<v8::FunctionTemplate>();")),
+            S("instance_template",
+              "v8::Local<v8::Template> ${instance_template};"),
+            S("prototype_template",
+              "v8::Local<v8::Template> ${prototype_template};"),
+            S("signature", "v8::Local<v8::Signature> ${signature};"),
+        ])
+
     # context_feature_settings
     node = S("context_feature_settings",
              ("const ContextFeatureSettings* ${context_feature_settings} = "
@@ -4232,8 +4267,9 @@
         # https://heycam.github.io/webidl/#named-properties-object
         _1 = " = ${npo_interface_template}"  # npo = named properties object
     elif interface.inherited:
-        _1 = (" = ${wrapper_type_info}->parent_class->dom_template_function"
-              "(${isolate}, ${world})")
+        _1 = (" = ${wrapper_type_info}->parent_class"
+              "->GetV8ClassTemplate(${isolate}, ${world})"
+              ".As<v8::FunctionTemplate>()")
     else:
         _1 = ""
     local_vars.append(S("parent_interface_template", _format(pattern, _1=_1)))
@@ -4247,12 +4283,13 @@
 v8::Local<v8::ObjectTemplate> ${npo_prototype_template} =
     ${npo_interface_template}->PrototypeTemplate();
 ${npo_interface_template}->Inherit(
-    ${wrapper_type_info}->parent_class->dom_template_function(
-        ${isolate}, ${world}));
+    ${wrapper_type_info}->parent_class
+    ->GetV8ClassTemplate(${isolate}, ${world}).As<v8::FunctionTemplate>());
 ${npo_prototype_template}->SetImmutableProto();
-V8DOMConfiguration::SetClassString(
-    ${isolate}, ${npo_prototype_template},
-    "${interface.identifier}Properties");
+${npo_prototype_template}->Set(
+    v8::Symbol::GetToStringTag(${isolate}),
+    V8AtomicString(${isolate}, "${interface.identifier}Properties"),
+    static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum));
 // Make the named properties object look like the global object.  Note that
 // the named properties object is _not_ a prototype object, plus, we'd like
 // the named properties object to behave just like the global object (= the
@@ -5057,7 +5094,7 @@
     arg_decls = [
         "v8::Isolate* isolate",
         "const DOMWrapperWorld& world",
-        "v8::Local<v8::FunctionTemplate> interface_template",
+        "v8::Local<v8::Template> interface_template",
     ]
     return_type = "void"
 
@@ -5095,18 +5132,38 @@
     })
     bind_installer_local_vars(body, cg_context)
 
-    body.extend([
-        T("V8DOMConfiguration::InitializeDOMInterfaceTemplate("
-          "${isolate}, ${interface_template}, "
-          "${wrapper_type_info}->interface_name, ${parent_interface_template}, "
-          "kV8DefaultWrapperInternalFieldCount);"),
-        EmptyNode(),
-    ])
+    if cg_context.interface:
+        body.extend([
+            T("bindings::SetupIDLInterfaceTemplates("
+              "${isolate}, ${wrapper_type_info}, "
+              "${instance_object_template}, "
+              "${prototype_object_template}, "
+              "${interface_function_template}, "
+              "${parent_interface_template});"),
+            EmptyNode(),
+        ])
+    elif cg_context.namespace:
+        body.extend([
+            T("bindings::SetupIDLNamespaceTemplate("
+              "${isolate}, ${wrapper_type_info}, "
+              "${interface_function_template});"),
+            EmptyNode(),
+        ])
+    elif cg_context.callback_interface:
+        body.extend([
+            T("bindings::SetupIDLCallbackInterfaceTemplate("
+              "${isolate}, ${wrapper_type_info}, "
+              "${interface_function_template});"),
+            EmptyNode(),
+        ])
+    else:
+        assert False
 
     for entry in constructor_entries:
-        set_callback = _format("${interface_template}->SetCallHandler({});",
-                               entry.ctor_callback_name)
-        set_length = _format("${interface_template}->SetLength({});",
+        set_callback = _format(
+            "${interface_function_template}->SetCallHandler({});",
+            entry.ctor_callback_name)
+        set_length = _format("${interface_function_template}->SetLength({});",
                              entry.ctor_func_length)
         if entry.world == CodeGenContext.MAIN_WORLD:
             body.append(
@@ -5124,12 +5181,6 @@
             assert False
         body.append(EmptyNode())
 
-    if cg_context.callback_interface:
-        body.extend([
-            T("${interface_template}->RemovePrototype();"),
-            EmptyNode(),
-        ])
-
     body.extend([
         supplemental_install_node,
         EmptyNode(),
@@ -5169,7 +5220,8 @@
   intrinsic_error_prototype_interface_template->RemovePrototype();
   intrinsic_error_prototype_interface_template->SetIntrinsicDataProperty(
       V8AtomicString(${isolate}, "prototype"), v8::kErrorPrototype);
-  ${interface_template}->Inherit(intrinsic_error_prototype_interface_template);
+  ${interface_function_template}->Inherit(
+      intrinsic_error_prototype_interface_template);
 }
 """))
 
@@ -5185,7 +5237,7 @@
   intrinsic_iterator_prototype_interface_template->RemovePrototype();
   intrinsic_iterator_prototype_interface_template->SetIntrinsicDataProperty(
       V8AtomicString(${isolate}, "prototype"), v8::kAsyncIteratorPrototype);
-  ${interface_template}->Inherit(
+  ${interface_function_template}->Inherit(
       intrinsic_iterator_prototype_interface_template);
 }
 """))
@@ -5195,9 +5247,9 @@
             T("""\
 // HTMLAllCollection-specific settings
 // https://html.spec.whatwg.org/C/#the-htmlallcollection-interface
-${instance_template}->SetCallAsFunctionHandler(
+${instance_object_template}->SetCallAsFunctionHandler(
     ${class_name}::LegacyCallCustom);
-${instance_template}->MarkAsUndetectable();
+${instance_object_template}->MarkAsUndetectable();
 """))
 
     if class_like.identifier == "Iterator":
@@ -5212,7 +5264,7 @@
   intrinsic_iterator_prototype_interface_template->RemovePrototype();
   intrinsic_iterator_prototype_interface_template->SetIntrinsicDataProperty(
       V8AtomicString(${isolate}, "prototype"), v8::kIteratorPrototype);
-  ${interface_template}->Inherit(
+  ${interface_function_template}->Inherit(
       intrinsic_iterator_prototype_interface_template);
 }
 """))
@@ -5243,8 +5295,8 @@
         v8::ReadOnly | v8::DontEnum | v8::DontDelete));
 // 7.7.4.2 [[SetPrototypeOf]] ( V )
 // https://html.spec.whatwg.org/C/#location-setprototypeof
-${instance_template}->SetImmutableProto();
-${prototype_template}->SetImmutableProto();
+${instance_object_template}->SetImmutableProto();
+${prototype_object_template}->SetImmutableProto();
 """))
 
     if (interface and interface.indexed_and_named_properties
@@ -5278,8 +5330,8 @@
 // [Global]
 // 3.7.1. [[SetPrototypeOf]]
 // https://heycam.github.io/webidl/#platform-object-setprototypeof
-${instance_template}->SetImmutableProto();
-${prototype_template}->SetImmutableProto();
+${instance_object_template}->SetImmutableProto();
+${prototype_object_template}->SetImmutableProto();
 """))
     elif interface and any("Global" in derived.extended_attributes
                            for derived in interface.deriveds):
@@ -5288,7 +5340,7 @@
 // [Global] - prototype object in the prototype chain of global objects
 // 3.7.1. [[SetPrototypeOf]]
 // https://heycam.github.io/webidl/#platform-object-setprototypeof
-${prototype_template}->SetImmutableProto();
+${prototype_object_template}->SetImmutableProto();
 """))
 
     func_call_pattern = ("{}(${isolate}, ${world}, ${instance_template}, "
@@ -5362,9 +5414,9 @@
         arg_decls = [
             "v8::Isolate* isolate",
             "const DOMWrapperWorld& world",
-            "v8::Local<v8::ObjectTemplate> instance_template",
-            "v8::Local<v8::ObjectTemplate> prototype_template",
-            "v8::Local<v8::FunctionTemplate> interface_template",
+            "v8::Local<v8::Template> instance_template",
+            "v8::Local<v8::Template> prototype_template",
+            "v8::Local<v8::Template> interface_template",
         ]
         arg_names = [
             "isolate",
@@ -5379,8 +5431,8 @@
             "const DOMWrapperWorld& world",
             "v8::Local<v8::Object> instance_object",
             "v8::Local<v8::Object> prototype_object",
-            "v8::Local<v8::Function> interface_object",
-            "v8::Local<v8::FunctionTemplate> interface_template",
+            "v8::Local<v8::Object> interface_object",
+            "v8::Local<v8::Template> interface_template",
             "FeatureSelector feature_selector",
         ]
         arg_names = [
@@ -5398,8 +5450,8 @@
             "const DOMWrapperWorld& world",
             "v8::Local<v8::Object> instance_object",
             "v8::Local<v8::Object> prototype_object",
-            "v8::Local<v8::Function> interface_object",
-            "v8::Local<v8::FunctionTemplate> interface_template",
+            "v8::Local<v8::Object> interface_object",
+            "v8::Local<v8::Template> interface_template",
         ]
         arg_names = [
             "context",
@@ -5508,16 +5560,16 @@
     if is_per_context_install:
         pattern = ("{install_func}("
                    "${isolate}, ${world}, "
-                   "v8::Local<v8::Object>(${instance_object}), "
-                   "v8::Local<v8::Object>(${prototype_object}), "
-                   "v8::Local<v8::Object>(${interface_object}), "
+                   "${instance_object}, "
+                   "${prototype_object}, "
+                   "${interface_object}, "
                    "${signature}, {table_name});")
     else:
         pattern = ("{install_func}("
                    "${isolate}, ${world}, "
-                   "v8::Local<v8::Template>(${instance_template}), "
-                   "v8::Local<v8::Template>(${prototype_template}), "
-                   "v8::Local<v8::Template>(${interface_template}), "
+                   "${instance_template}, "
+                   "${prototype_template}, "
+                   "${interface_template}, "
                    "${signature}, {table_name});")
 
     table_name = "kAttributeTable"
@@ -5649,7 +5701,7 @@
                 map(lambda flag: "int32_t({})".format(flag), flags))))
         pattern = """\
 // Named interceptors
-${instance_template}->SetHandler(
+${instance_object_template}->SetHandler(
     v8::NamedPropertyHandlerConfiguration(
         {impl_bridge}::NamedPropertyGetterCallback,
         {impl_bridge}::NamedPropertySetterCallback,
@@ -5708,7 +5760,7 @@
         property_handler_flags = flags[0]
         pattern = """\
 // Indexed interceptors
-${instance_template}->SetHandler(
+${instance_object_template}->SetHandler(
     v8::IndexedPropertyHandlerConfiguration(
         {impl_bridge}::IndexedPropertyGetterCallback,
         {impl_bridge}::IndexedPropertySetterCallback,
@@ -5943,7 +5995,7 @@
 
     text = """\
 // Cross origin properties
-${instance_template}->SetAccessCheckCallbackAndHandler(
+${instance_object_template}->SetAccessCheckCallbackAndHandler(
     CrossOriginAccessCheckCallback,
     v8::NamedPropertyHandlerConfiguration(
         CrossOriginNamedGetterCallback,
@@ -6001,7 +6053,7 @@
 
     text = """\
 // Same origin interceptors
-${instance_template}->SetHandler(
+${instance_object_template}->SetHandler(
     v8::IndexedPropertyHandlerConfiguration(
         SameOriginIndexedGetterCallback,
         SameOriginIndexedSetterCallback,
@@ -6126,35 +6178,6 @@
     wrapper_type_info_def.set_base_template_vars(
         cg_context.template_bindings())
 
-    wrapper_type_info_def.append(
-        TextNode("""\
-// Migration adapters
-v8::Local<v8::FunctionTemplate> ${class_name}::DomTemplate(
-    v8::Isolate* isolate,
-    const DOMWrapperWorld& world) {
-  return V8DOMConfiguration::DomClassTemplate(
-      isolate, world,
-      const_cast<WrapperTypeInfo*>(${class_name}::GetWrapperTypeInfo()),
-      ${class_name}::InstallInterfaceTemplate);
-}
-"""))
-    if has_context_dependent_props:
-        pattern = """\
-static void InstallContextDependentPropertiesAdapter(
-    v8::Local<v8::Context> context,
-    const DOMWrapperWorld& world,
-    v8::Local<v8::Object> instance_object,
-    v8::Local<v8::Object> prototype_object,
-    v8::Local<v8::Function> interface_object,
-    v8::Local<v8::FunctionTemplate> interface_template) {{
-  ${class_name}::{}(
-      context, world, instance_object, prototype_object, interface_object,
-      interface_template,
-      bindings::V8InterfaceBridgeBase::FeatureSelector());
-}}
-"""
-        wrapper_type_info_def.append(
-            F(pattern, FN_INSTALL_CONTEXT_DEPENDENT_PROPS))
     pattern = """\
 // Construction of WrapperTypeInfo may require non-trivial initialization due
 // to cross-component address resolution in order to load the pointer to the
@@ -6168,13 +6191,14 @@
 
 const WrapperTypeInfo ${class_name}::wrapper_type_info_{{
     gin::kEmbedderBlink,
-    ${class_name}::DomTemplate,
+    ${class_name}::{install_interface_template_func},
     {install_context_dependent_func},
     "${{class_like.identifier}}",
     {wrapper_type_info_of_inherited},
     {wrapper_type_prototype},
     {wrapper_class_id},
     {active_script_wrappable_inheritance},
+    {idl_definition_kind},
 }};
 
 #if defined(COMPONENT_BUILD) && defined(WIN32) && defined(__clang__)
@@ -6183,8 +6207,8 @@
 """
     class_like = cg_context.class_like
     if has_context_dependent_props:
-        install_context_dependent_func = (
-            "InstallContextDependentPropertiesAdapter")
+        install_context_dependent_func = _format(
+            "${class_name}::{}", FN_INSTALL_CONTEXT_DEPENDENT_PROPS)
     else:
         install_context_dependent_func = "nullptr"
     if class_like.is_interface and class_like.inherited:
@@ -6192,25 +6216,36 @@
             v8_bridge_class_name(class_like.inherited))
     else:
         wrapper_type_info_of_inherited = "nullptr"
-    wrapper_type_prototype = ("WrapperTypeInfo::kWrapperTypeObjectPrototype"
-                              if class_like.is_interface else
-                              "WrapperTypeInfo::kWrapperTypeNoPrototype")
-    wrapper_class_id = ("WrapperTypeInfo::kNodeClassId"
-                        if class_like.is_interface
-                        and class_like.does_implement("Node") else
-                        "WrapperTypeInfo::kObjectClassId")
-    active_script_wrappable_inheritance = (
-        "WrapperTypeInfo::kInheritFromActiveScriptWrappable"
-        if class_like.code_generator_info.is_active_script_wrappable else
-        "WrapperTypeInfo::kNotInheritFromActiveScriptWrappable")
+    if class_like.is_interface:
+        wrapper_type_prototype = "WrapperTypeInfo::kWrapperTypeObjectPrototype"
+    else:
+        wrapper_type_prototype = "WrapperTypeInfo::kWrapperTypeNoPrototype"
+    if class_like.is_interface and class_like.does_implement("Node"):
+        wrapper_class_id = "WrapperTypeInfo::kNodeClassId"
+    else:
+        wrapper_class_id = "WrapperTypeInfo::kObjectClassId"
+    if class_like.code_generator_info.is_active_script_wrappable:
+        active_script_wrappable_inheritance = (
+            "WrapperTypeInfo::kInheritFromActiveScriptWrappable")
+    else:
+        active_script_wrappable_inheritance = (
+            "WrapperTypeInfo::kNotInheritFromActiveScriptWrappable")
+    if class_like.is_interface:
+        idl_definition_kind = "WrapperTypeInfo::kIdlInterface"
+    elif class_like.is_namespace:
+        idl_definition_kind = "WrapperTypeInfo::kIdlNamespace"
+    elif class_like.is_callback_interface:
+        idl_definition_kind = "WrapperTypeInfo::kIdlCallbackInterface"
     wrapper_type_info_def.append(
         F(pattern,
+          install_interface_template_func=FN_INSTALL_INTERFACE_TEMPLATE,
           install_context_dependent_func=install_context_dependent_func,
           wrapper_type_info_of_inherited=wrapper_type_info_of_inherited,
           wrapper_type_prototype=wrapper_type_prototype,
           wrapper_class_id=wrapper_class_id,
           active_script_wrappable_inheritance=(
-              active_script_wrappable_inheritance)))
+              active_script_wrappable_inheritance),
+          idl_definition_kind=idl_definition_kind))
 
     if class_like.is_interface:
         blink_class = blink_class_name(class_like)
@@ -6392,9 +6427,9 @@
     arg_decls = [
         "v8::Isolate* isolate",
         "const DOMWrapperWorld& world",
-        "v8::Local<v8::ObjectTemplate> instance_template",
-        "v8::Local<v8::ObjectTemplate> prototype_template",
-        "v8::Local<v8::FunctionTemplate> interface_template",
+        "v8::Local<v8::Template> instance_template",
+        "v8::Local<v8::Template> prototype_template",
+        "v8::Local<v8::Template> interface_template",
     ]
     arg_names = [
         "isolate",
@@ -6897,9 +6932,6 @@
         component_export_header(api_component, for_testing),
         "third_party/blink/renderer/platform/bindings/v8_interface_bridge.h",
     ])
-    api_source_node.accumulator.add_include_headers([
-        "third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.h",
-    ])
     if interface.inherited:
         api_source_node.accumulator.add_include_headers(
             [PathManager(interface.inherited).api_path(ext="h")])
@@ -6909,8 +6941,8 @@
             component_export_header(impl_component, for_testing),
         ])
     impl_source_node.accumulator.add_include_headers([
+        "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h",
         "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h",
-        "third_party/blink/renderer/bindings/core/v8/v8_dom_configuration.h",
         "third_party/blink/renderer/bindings/core/v8/v8_set_return_value_for_core.h",
         "third_party/blink/renderer/platform/bindings/exception_messages.h",
         "third_party/blink/renderer/platform/bindings/idl_member_installer.h",
@@ -6940,13 +6972,6 @@
 
     api_class_def.public_section.append(get_wrapper_type_info_def)
     api_class_def.public_section.append(EmptyNode())
-    api_class_def.public_section.extend([
-        TextNode("// Migration adapter"),
-        TextNode("static v8::Local<v8::FunctionTemplate> DomTemplate("
-                 "v8::Isolate* isolate, "
-                 "const DOMWrapperWorld& world);"),
-        EmptyNode(),
-    ])
     api_class_def.private_section.append(wrapper_type_info_var_def)
     api_class_def.private_section.append(EmptyNode())
     api_source_blink_ns.body.extend([
@@ -7220,14 +7245,14 @@
   v8::Local<v8::Object> instance_object;
   v8::Local<v8::Object> prototype_object;
   v8::Local<v8::Function> interface_object;
-  v8::Local<v8::FunctionTemplate> interface_template;
+  v8::Local<v8::Template> interface_template;
 
   if (!per_context_data->GetExistingConstructorAndPrototypeForType(
           wrapper_type_info, &prototype_object, &interface_object)) {
     continue;
   }
 
-  interface_template = wrapper_type_info->DomTemplate(isolate, world);
+  interface_template = wrapper_type_info->GetV8ClassTemplate(isolate, world);
   install_func(context, world, instance_object, prototype_object,
                interface_object, interface_template, feature_selector);
 }\
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py b/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py
index eeabef97..8ecef23 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py
@@ -168,3 +168,8 @@
     def exposed_constructs(self):
         """Returns exposed constructs."""
         return ()
+
+    # UserDefinedType overrides
+    @property
+    def is_namespace(self):
+        return True
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/user_defined_type.py b/third_party/blink/renderer/bindings/scripts/web_idl/user_defined_type.py
index e7858c07..6408bb8 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/user_defined_type.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/user_defined_type.py
@@ -17,16 +17,6 @@
         WithIdentifier.__init__(self, identifier)
 
     @property
-    def is_interface(self):
-        """Returns True if this is an IDL interface."""
-        return False
-
-    @property
-    def is_dictionary(self):
-        """Returns True if this is an IDL dictionary."""
-        return False
-
-    @property
     def is_callback_function(self):
         """Returns True if this is an IDL callback function."""
         return False
@@ -37,10 +27,25 @@
         return False
 
     @property
+    def is_dictionary(self):
+        """Returns True if this is an IDL dictionary."""
+        return False
+
+    @property
     def is_enumeration(self):
         """Returns True if this is an IDL enumeration."""
         return False
 
+    @property
+    def is_interface(self):
+        """Returns True if this is an IDL interface."""
+        return False
+
+    @property
+    def is_namespace(self):
+        """Returns True if this is an IDL namespace."""
+        return False
+
 
 class StubUserDefinedType(UserDefinedType, WithComponent):
     def __init__(self, identifier):
diff --git a/third_party/blink/renderer/controller/blink_initializer.cc b/third_party/blink/renderer/controller/blink_initializer.cc
index 0231bcf..a6ebefa 100644
--- a/third_party/blink/renderer/controller/blink_initializer.cc
+++ b/third_party/blink/renderer/controller/blink_initializer.cc
@@ -194,6 +194,11 @@
   Agent::SetIsCrossOriginIsolated(value);
 }
 
+// Function defined in third_party/blink/public/web/blink.h.
+bool IsCrossOriginIsolated() {
+  return Agent::IsCrossOriginIsolated();
+}
+
 void BlinkInitializer::RegisterInterfaces(mojo::BinderMap& binders) {
   ModulesInitializer::RegisterInterfaces(binders);
   Thread* main_thread = Thread::MainThread();
diff --git a/third_party/blink/renderer/core/css/style_media.cc b/third_party/blink/renderer/core/css/style_media.cc
index 2faa9e70..8f8882d 100644
--- a/third_party/blink/renderer/core/css/style_media.cc
+++ b/third_party/blink/renderer/core/css/style_media.cc
@@ -34,31 +34,28 @@
 
 namespace blink {
 
-StyleMedia::StyleMedia(LocalFrame* frame) : ExecutionContextClient(frame) {}
+StyleMedia::StyleMedia(LocalDOMWindow* window)
+    : ExecutionContextClient(window) {}
 
 AtomicString StyleMedia::type() const {
-  LocalFrameView* view = GetFrame() ? GetFrame()->View() : nullptr;
-  if (view)
-    return view->MediaType();
-
-  return g_null_atom;
+  if (!DomWindow())
+    return g_null_atom;
+  return DomWindow()->GetFrame()->View()->MediaType();
 }
 
 bool StyleMedia::matchMedium(const String& query) const {
-  if (!GetFrame())
+  if (!DomWindow())
     return false;
 
-  Document* document = GetFrame()->GetDocument();
-  DCHECK(document);
-  Element* document_element = document->documentElement();
+  Element* document_element = DomWindow()->document()->documentElement();
   if (!document_element)
     return false;
 
   scoped_refptr<MediaQuerySet> media = MediaQuerySet::Create();
-  if (!media->Set(query, GetFrame()->DomWindow()))
+  if (!media->Set(query, DomWindow()))
     return false;
 
-  MediaQueryEvaluator screen_eval(GetFrame());
+  MediaQueryEvaluator screen_eval(DomWindow()->GetFrame());
   return screen_eval.Eval(*media);
 }
 
diff --git a/third_party/blink/renderer/core/css/style_media.h b/third_party/blink/renderer/core/css/style_media.h
index f0635698..eeb5ef5 100644
--- a/third_party/blink/renderer/core/css/style_media.h
+++ b/third_party/blink/renderer/core/css/style_media.h
@@ -34,13 +34,13 @@
 
 namespace blink {
 
-class LocalFrame;
+class LocalDOMWindow;
 
 class StyleMedia final : public ScriptWrappable, public ExecutionContextClient {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit StyleMedia(LocalFrame*);
+  explicit StyleMedia(LocalDOMWindow*);
 
   AtomicString type() const;
   bool matchMedium(const String&) const;
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 37f0f601e..cbdb3ad5 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -33,7 +33,7 @@
 // instead of including more headers. If that is infeasible, adjust the limit.
 // For more info, see
 // https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
-#pragma clang max_tokens_here 960000
+#pragma clang max_tokens_here 980000
 
 #include <memory>
 #include <utility>
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
index 53bf8ce..95a9de3 100644
--- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
@@ -819,7 +819,6 @@
 WebPluginContainerImpl::WebPluginContainerImpl(HTMLPlugInElement& element,
                                                WebPlugin* web_plugin)
     : EmbeddedContentView(IntRect()),
-      ExecutionContextClient(element.GetDocument().GetFrame()),
       element_(element),
       web_plugin_(web_plugin),
       layer_(nullptr),
@@ -875,7 +874,6 @@
 void WebPluginContainerImpl::Trace(Visitor* visitor) const {
   visitor->Trace(element_);
   visitor->Trace(mouse_lock_lost_listener_);
-  ExecutionContextClient::Trace(visitor);
 }
 
 void WebPluginContainerImpl::HandleMouseEvent(MouseEvent& event) {
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.h b/third_party/blink/renderer/core/exported/web_plugin_container_impl.h
index f304e679f..7a74505 100644
--- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.h
+++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.h
@@ -71,8 +71,7 @@
 class CORE_EXPORT WebPluginContainerImpl final
     : public GarbageCollected<WebPluginContainerImpl>,
       public EmbeddedContentView,
-      public WebPluginContainer,
-      public ExecutionContextClient {
+      public WebPluginContainer {
   USING_PRE_FINALIZER(WebPluginContainerImpl, PreFinalize);
 
  public:
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index 7628826..2e01ca45 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -925,7 +925,7 @@
         this, WebFeature::kApplicationCacheAPIInsecureOrigin);
   }
   if (!application_cache_)
-    application_cache_ = MakeGarbageCollected<ApplicationCache>(GetFrame());
+    application_cache_ = MakeGarbageCollected<ApplicationCache>(this);
   return application_cache_.Get();
 }
 
@@ -1447,9 +1447,9 @@
   return document_.Get();
 }
 
-StyleMedia* LocalDOMWindow::styleMedia() const {
+StyleMedia* LocalDOMWindow::styleMedia() {
   if (!media_)
-    media_ = MakeGarbageCollected<StyleMedia>(GetFrame());
+    media_ = MakeGarbageCollected<StyleMedia>(this);
   return media_.Get();
 }
 
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h
index 6b81f99..f52dea4 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.h
+++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -238,7 +238,7 @@
   Document* document() const;
 
   // CSSOM View Module
-  StyleMedia* styleMedia() const;
+  StyleMedia* styleMedia();
 
   // WebKit extensions
   double devicePixelRatio() const;
diff --git a/third_party/blink/renderer/core/frame/screen.cc b/third_party/blink/renderer/core/frame/screen.cc
index 0fca1d4..50c1228b 100644
--- a/third_party/blink/renderer/core/frame/screen.cc
+++ b/third_party/blink/renderer/core/frame/screen.cc
@@ -156,7 +156,7 @@
                bool internal,
                bool primary,
                const String& id)
-    : ExecutionContextClient(static_cast<LocalFrame*>(nullptr)),
+    : ExecutionContextClient(static_cast<ExecutionContext*>(nullptr)),
       display_(std::move(display)),
       internal_(internal),
       primary_(primary),
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
index 3cda618..dca985e0 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
@@ -183,7 +183,13 @@
                  ThreadScheduler::Current()->DeprecatedDefaultTaskRunner());
 }
 
-WebFrameWidgetBase::~WebFrameWidgetBase() = default;
+WebFrameWidgetBase::~WebFrameWidgetBase() {
+  // Ensure that Close is called and we aren't releasing |widget_base_| in the
+  // destructor.
+  // TODO(crbug.com/1139104): This CHECK can be changed to a DCHECK once
+  // the issue is solved.
+  CHECK(!widget_base_);
+}
 
 void WebFrameWidgetBase::BindLocalRoot(WebLocalFrame& local_root) {
   local_root_ = To<WebLocalFrameImpl>(local_root);
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_base.h b/third_party/blink/renderer/core/frame/web_frame_widget_base.h
index 4cec50d..ade9ccd1 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_base.h
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_base.h
@@ -322,7 +322,6 @@
   void CancelCompositionForPepper() override;
   void ApplyVisualProperties(
       const VisualProperties& visual_properties) override;
-  bool IsFullscreenGranted() override;
   bool PinchGestureActiveInMainFrame() override;
   float PageScaleInMainFrame() override;
   const ScreenInfo& GetScreenInfo() override;
@@ -616,6 +615,9 @@
   void PointerLockMouseEvent(const WebCoalescedInputEvent&);
   bool IsPointerLocked();
 
+  // The fullscreen granted status from the most recent VisualProperties update.
+  bool IsFullscreenGranted();
+
   virtual PageWidgetEventHandler* GetPageWidgetEventHandler() = 0;
 
   // Return the LocalFrameView used for animation scrolling. This is overridden
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index ca7f591..8e0d982 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -661,6 +661,9 @@
       SetNeedsPaintPropertyUpdate();
     }
 
+    if (old_style->OverflowClipMargin() != new_style.OverflowClipMargin())
+      SetNeedsPaintPropertyUpdate();
+
     if (IsInLayoutNGInlineFormattingContext() && IsAtomicInlineLevel() &&
         old_style->Direction() != new_style.Direction()) {
       SetNeedsCollectInlines();
@@ -2757,7 +2760,9 @@
     clip_rect.Move(location);
     if (HasNonVisibleOverflow()) {
       const auto overflow_clip = GetOverflowClipAxes();
-      if (overflow_clip != kOverflowClipBothAxis) {
+      if (overflow_clip == kOverflowClipBothAxis) {
+        clip_rect.Inflate(StyleRef().OverflowClipMargin());
+      } else {
         auto infinite_rect = LayoutRect::InfiniteIntRect();
         if ((overflow_clip & kOverflowClipX) == kNoOverflowClip) {
           clip_rect.offset.left = LayoutUnit(infinite_rect.X());
@@ -7185,8 +7190,11 @@
   // Only propagate interior layout overflow if we don't clip it.
   LayoutRect rect = BorderBoxRect();
 
-  if (!ShouldApplyLayoutContainment() && !ShouldClipOverflowAlongBothAxis())
+  if (!ShouldApplyLayoutContainment() &&
+      (!ShouldClipOverflowAlongBothAxis() ||
+       StyleRef().OverflowClipMargin() != LayoutUnit())) {
     rect.Unite(LayoutOverflowRect());
+  }
 
   bool has_transform = HasLayer() && Layer()->Transform();
   if (IsInFlowPositioned() || has_transform) {
@@ -7226,11 +7234,32 @@
   NOT_DESTROYED();
   if (!VisualOverflowIsSet())
     return BorderBoxRect();
-  const OverflowClipAxes overflow_clip_axes = GetOverflowClipAxes();
-  if (overflow_clip_axes == kOverflowClipBothAxis || HasMask())
-    return overflow_->visual_overflow->SelfVisualOverflowRect();
+
   const LayoutRect& self_visual_overflow_rect =
       overflow_->visual_overflow->SelfVisualOverflowRect();
+  if (HasMask())
+    return self_visual_overflow_rect;
+
+  const OverflowClipAxes overflow_clip_axes = GetOverflowClipAxes();
+  const LayoutUnit overflow_clip_margin = StyleRef().OverflowClipMargin();
+  if (overflow_clip_margin != LayoutUnit()) {
+    // overflow_clip_margin should only be set if 'overflow' is 'clip' along
+    // both axis.
+    DCHECK_EQ(overflow_clip_axes, kOverflowClipBothAxis);
+    const LayoutRect& contents_visual_overflow_rect =
+        overflow_->visual_overflow->ContentsVisualOverflowRect();
+    if (!contents_visual_overflow_rect.IsEmpty()) {
+      LayoutRect result = BorderBoxRect();
+      result.Inflate(overflow_clip_margin);
+      result.Intersect(contents_visual_overflow_rect);
+      result.Unite(self_visual_overflow_rect);
+      return result;
+    }
+  }
+
+  if (overflow_clip_axes == kOverflowClipBothAxis)
+    return self_visual_overflow_rect;
+
   LayoutRect result = overflow_->visual_overflow->ContentsVisualOverflowRect();
   result.Unite(self_visual_overflow_rect);
   ApplyOverflowClip(overflow_clip_axes, self_visual_overflow_rect, result);
@@ -7688,9 +7717,18 @@
   if (overflow_clip_axes == kNoOverflowClip)
     return;
 
-  const LayoutRect no_overflow_rect = NoOverflowRect();
+  LayoutRect no_overflow_rect = NoOverflowRect();
   LayoutRect overflow_rect = overflow_->layout_overflow->LayoutOverflowRect();
-  ApplyOverflowClip(overflow_clip_axes, no_overflow_rect, overflow_rect);
+  const LayoutUnit overflow_clip_margin = StyleRef().OverflowClipMargin();
+  if (overflow_clip_margin != LayoutUnit()) {
+    // overflow_clip_margin should only be set if 'overflow' is 'clip' along
+    // both axis.
+    DCHECK_EQ(overflow_clip_axes, kOverflowClipBothAxis);
+    no_overflow_rect.Inflate(overflow_clip_margin);
+    overflow_rect.Intersect(no_overflow_rect);
+  } else {
+    ApplyOverflowClip(overflow_clip_axes, no_overflow_rect, overflow_rect);
+  }
   overflow_->layout_overflow->SetLayoutOverflow(overflow_rect);
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_box_test.cc b/third_party/blink/renderer/core/layout/layout_box_test.cc
index 0e2fe7e..45c275e 100644
--- a/third_party/blink/renderer/core/layout/layout_box_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_test.cc
@@ -513,6 +513,57 @@
   EXPECT_EQ(LayoutRect(0, 0, 300, 50), clip_y->VisualOverflowRect());
 }
 
+TEST_P(LayoutBoxTest, VisualOverflowRectWithOverflowClipMargin) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      .parent { width: 100px; height: 50px; overflow: clip; }
+      .child { width: 110px; height: 55px; }
+    </style>
+    <div id="clip1" style="overflow-clip-margin: 4px" class="parent">
+      <div class="child"></div>
+    </div>
+    <div id="clip2" style="overflow-clip-margin: 11px" class="parent">
+      <div class="child"></div>
+    </div>
+  )HTML");
+
+  LayoutBox* clip1 = GetLayoutBoxByElementId("clip1");
+  EXPECT_FALSE(clip1->IsScrollContainer());
+  EXPECT_TRUE(clip1->ShouldClipOverflowAlongBothAxis());
+  EXPECT_EQ(LayoutRect(0, 0, 104, 54), clip1->VisualOverflowRect());
+
+  LayoutBox* clip2 = GetLayoutBoxByElementId("clip2");
+  EXPECT_FALSE(clip2->IsScrollContainer());
+  EXPECT_TRUE(clip2->ShouldClipOverflowAlongBothAxis());
+  EXPECT_EQ(LayoutRect(0, 0, 110, 55), clip2->VisualOverflowRect());
+}
+
+TEST_P(LayoutBoxTest, LayoutOverflowRectWithOverflowClipMargin) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      .parent { width: 100px; height: 50px; overflow: clip; }
+      .child { position: relative; top: -5px; left: -6px; width: 110px;
+               height: 112px; }
+    </style>
+    <div id="clip1" style="overflow-clip-margin: 4px" class="parent">
+      <div class="child"></div>
+    </div>
+    <div id="clip2" style="overflow-clip-margin: 10px" class="parent">
+      <div class="child"></div>
+    </div>
+  )HTML");
+
+  LayoutBox* clip1 = GetLayoutBoxByElementId("clip1");
+  EXPECT_FALSE(clip1->IsScrollContainer());
+  EXPECT_TRUE(clip1->ShouldClipOverflowAlongBothAxis());
+  EXPECT_EQ(LayoutRect(-4, -4, 108, 58), clip1->LayoutOverflowRect());
+
+  LayoutBox* clip2 = GetLayoutBoxByElementId("clip2");
+  EXPECT_FALSE(clip2->IsScrollContainer());
+  EXPECT_TRUE(clip2->ShouldClipOverflowAlongBothAxis());
+  EXPECT_EQ(LayoutRect(-6, -5, 110, 65), clip2->LayoutOverflowRect());
+}
+
 TEST_P(LayoutBoxTest, ContentsVisualOverflowPropagation) {
   SetBodyInnerHTML(R"HTML(
     <style>
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_overflow_calculator.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_overflow_calculator.cc
index b1842a7..f8a0036 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_overflow_calculator.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_overflow_calculator.cc
@@ -94,13 +94,23 @@
   // Adjust the layout-overflow if we have "overflow: clip" present.
   if (!is_scroll_container_ && has_non_visible_overflow_) {
     const OverflowClipAxes overflow_clip_axes = node_.GetOverflowClipAxes();
-    if (overflow_clip_axes & kOverflowClipX) {
-      layout_overflow_.offset.left = padding_rect_.offset.left;
-      layout_overflow_.size.width = padding_rect_.size.width;
-    }
-    if (overflow_clip_axes & kOverflowClipY) {
-      layout_overflow_.offset.top = padding_rect_.offset.top;
-      layout_overflow_.size.height = padding_rect_.size.height;
+    const LayoutUnit overflow_clip_margin = node_.Style().OverflowClipMargin();
+    if (overflow_clip_margin != LayoutUnit()) {
+      // overflow_clip_margin should only be set if 'overflow' is 'clip' along
+      // both axis.
+      DCHECK_EQ(overflow_clip_axes, kOverflowClipBothAxis);
+      PhysicalRect expanded_padding_rect = padding_rect_;
+      expanded_padding_rect.Inflate(overflow_clip_margin);
+      layout_overflow_.Intersect(expanded_padding_rect);
+    } else {
+      if (overflow_clip_axes & kOverflowClipX) {
+        layout_overflow_.offset.left = padding_rect_.offset.left;
+        layout_overflow_.size.width = padding_rect_.size.width;
+      }
+      if (overflow_clip_axes & kOverflowClipY) {
+        layout_overflow_.offset.top = padding_rect_.offset.top;
+        layout_overflow_.size.height = padding_rect_.size.height;
+      }
     }
   }
 
@@ -275,7 +285,8 @@
   // layout overflow.
   PhysicalRect overflow = {{}, child_fragment.Size()};
   if (!child_fragment.ShouldApplyLayoutContainment() &&
-      !child_fragment.ShouldClipOverflowAlongBothAxis() &&
+      (!child_fragment.ShouldClipOverflowAlongBothAxis() ||
+       child_fragment.Style().OverflowClipMargin() != LayoutUnit()) &&
       !child_fragment.IsInlineBox())
     overflow.UniteEvenIfEmpty(child_fragment.LayoutOverflow());
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
index f75694a..b404cf3 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
@@ -613,9 +613,7 @@
   EXPECT_EQ(expectation, dump);
 }
 
-// TODO(bebeaudr): Enable when http://crbug.com/1115584 is fixed.
-TEST_F(NGOutOfFlowLayoutPartTest,
-       DISABLED_PositionedFragmentationWithBottomProperty) {
+TEST_F(NGOutOfFlowLayoutPartTest, PositionedFragmentationWithBottomProperty) {
   SetBodyInnerHTML(
       R"HTML(
       <style>
diff --git a/third_party/blink/renderer/core/loader/appcache/application_cache.cc b/third_party/blink/renderer/core/loader/appcache/application_cache.cc
index 6ec475cd..69d8bd7 100644
--- a/third_party/blink/renderer/core/loader/appcache/application_cache.cc
+++ b/third_party/blink/renderer/core/loader/appcache/application_cache.cc
@@ -30,18 +30,16 @@
 #include "third_party/blink/renderer/core/dom/events/event_listener.h"
 #include "third_party/blink/renderer/core/frame/deprecation.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/loader/appcache/application_cache_host_for_frame.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/core/loader/frame_loader.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 
 namespace blink {
 
-ApplicationCache::ApplicationCache(LocalFrame* frame)
-    : ExecutionContextClient(frame) {
-  DCHECK(RuntimeEnabledFeatures::AppCacheEnabled(frame->DomWindow()));
+ApplicationCache::ApplicationCache(LocalDOMWindow* window)
+    : ExecutionContextClient(window) {
+  DCHECK(RuntimeEnabledFeatures::AppCacheEnabled(window));
   ApplicationCacheHostForFrame* cache_host = GetApplicationCacheHost();
   if (cache_host)
     cache_host->SetApplicationCache(this);
@@ -54,9 +52,9 @@
 
 ApplicationCacheHostForFrame* ApplicationCache::GetApplicationCacheHost()
     const {
-  if (!GetFrame() || !GetFrame()->Loader().GetDocumentLoader())
+  if (!DomWindow())
     return nullptr;
-  return GetFrame()->Loader().GetDocumentLoader()->GetApplicationCacheHost();
+  return DomWindow()->document()->Loader()->GetApplicationCacheHost();
 }
 
 uint16_t ApplicationCache::status() const {
@@ -120,7 +118,7 @@
 }
 
 ExecutionContext* ApplicationCache::GetExecutionContext() const {
-  return GetFrame() ? GetFrame()->DomWindow() : nullptr;
+  return ExecutionContextClient::GetExecutionContext();
 }
 
 const AtomicString& ApplicationCache::ToEventType(mojom::AppCacheEventID id) {
@@ -147,11 +145,10 @@
 }
 
 void ApplicationCache::RecordAPIUseType() const {
-  if (!GetFrame())
+  if (!DomWindow())
     return;
-  LocalDOMWindow* window = GetFrame()->DomWindow();
-  CHECK(GetFrame()->DomWindow()->IsSecureContext());
-  Deprecation::CountDeprecation(window,
+  CHECK(DomWindow()->IsSecureContext());
+  Deprecation::CountDeprecation(DomWindow(),
                                 WebFeature::kApplicationCacheAPISecureOrigin);
 }
 
diff --git a/third_party/blink/renderer/core/loader/appcache/application_cache.h b/third_party/blink/renderer/core/loader/appcache/application_cache.h
index 1be1aa5c..4f5c07ad 100644
--- a/third_party/blink/renderer/core/loader/appcache/application_cache.h
+++ b/third_party/blink/renderer/core/loader/appcache/application_cache.h
@@ -36,14 +36,14 @@
 
 class ApplicationCacheHostForFrame;
 class ExceptionState;
-class LocalFrame;
+class LocalDOMWindow;
 
 class ApplicationCache final : public EventTargetWithInlineData,
                                public ExecutionContextClient {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit ApplicationCache(LocalFrame*);
+  explicit ApplicationCache(LocalDOMWindow*);
   ~ApplicationCache() override = default;
 
   uint16_t status() const;
diff --git a/third_party/blink/renderer/core/streams/readable_stream.idl b/third_party/blink/renderer/core/streams/readable_stream.idl
index e2d7d38..f27029ca 100644
--- a/third_party/blink/renderer/core/streams/readable_stream.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream.idl
@@ -7,15 +7,14 @@
     Exposed=(Window,Worker,Worklet)
 ] interface ReadableStream {
     [CallWith=ScriptState, RaisesException] constructor(optional any underlyingSource, optional any strategy);
-    [NotEnumerable] readonly attribute boolean locked;
+    readonly attribute boolean locked;
 
     // TODO(yhirano): function length is different from what's specced. Fix it.
-    [RaisesException, CallWith=ScriptState, NotEnumerable] Promise<any> cancel(
-        optional any reason);
-    [RaisesException, CallWith=ScriptState, NotEnumerable, MeasureAs=ReadableStreamGetReader] ReadableStreamDefaultReader getReader(optional any mode);
-    [RaisesException, CallWith=ScriptState, NotEnumerable, MeasureAs=ReadableStreamPipeThrough] any pipeThrough(
+    [RaisesException, CallWith=ScriptState] Promise<any> cancel(optional any reason);
+    [RaisesException, CallWith=ScriptState, MeasureAs=ReadableStreamGetReader] ReadableStreamDefaultReader getReader(optional any mode);
+    [RaisesException, CallWith=ScriptState, MeasureAs=ReadableStreamPipeThrough] any pipeThrough(
         any transformStream, optional any options);
-    [RaisesException, CallWith=ScriptState, NotEnumerable, MeasureAs=ReadableStreamPipeTo] Promise<any> pipeTo(
+    [RaisesException, CallWith=ScriptState, MeasureAs=ReadableStreamPipeTo] Promise<any> pipeTo(
         any destination, optional any option);
-    [RaisesException, CallWith=ScriptState, NotEnumerable] any tee();
+    [RaisesException, CallWith=ScriptState] any tee();
 };
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl b/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl
index e605a1a..33c8066 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_controller.idl
@@ -4,9 +4,9 @@
 
 // https://streams.spec.whatwg.org/#rs-default-controller-class-definition
 interface ReadableStreamDefaultController {
-    [NotEnumerable] readonly attribute double? desiredSize;
-    [CallWith=ScriptState, NotEnumerable, RaisesException] void close();
-    [CallWith=ScriptState, NotEnumerable, RaisesException] void enqueue(
+    readonly attribute double? desiredSize;
+    [CallWith=ScriptState, RaisesException] void close();
+    [CallWith=ScriptState, RaisesException] void enqueue(
         optional any chunk);
-    [CallWith=ScriptState, NotEnumerable] void error(optional any e);
+    [CallWith=ScriptState] void error(optional any e);
 };
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl b/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
index 5fb3288d..2e338483 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
@@ -8,11 +8,11 @@
     ImplementedAs=ReadableStreamReader
 ] interface ReadableStreamDefaultReader {
     [CallWith=ScriptState, RaisesException] constructor(ReadableStream stream);
-    [CallWith=ScriptState, NotEnumerable] readonly attribute Promise<void>
+    [CallWith=ScriptState] readonly attribute Promise<void>
         closed;
 
-    [CallWith=ScriptState, RaisesException, NotEnumerable] Promise<void> cancel(
+    [CallWith=ScriptState, RaisesException] Promise<void> cancel(
         optional any reason);
-    [CallWith=ScriptState, RaisesException, NotEnumerable] Promise<void> read();
-    [CallWith=ScriptState, NotEnumerable, RaisesException] void releaseLock();
+    [CallWith=ScriptState, RaisesException] Promise<void> read();
+    [CallWith=ScriptState, RaisesException] void releaseLock();
 };
diff --git a/third_party/blink/renderer/core/streams/writable_stream.idl b/third_party/blink/renderer/core/streams/writable_stream.idl
index 8cb0ff8..bb61c20 100644
--- a/third_party/blink/renderer/core/streams/writable_stream.idl
+++ b/third_party/blink/renderer/core/streams/writable_stream.idl
@@ -7,9 +7,9 @@
     Exposed=(Window,Worker,Worklet)
 ] interface WritableStream {
     [CallWith=ScriptState, RaisesException, MeasureAs=WritableStreamConstructor] constructor(optional any underlyingSink, optional any strategy);
-    [NotEnumerable] readonly attribute boolean locked;
-    [RaisesException, CallWith=ScriptState, NotEnumerable] Promise<void> abort(
+    readonly attribute boolean locked;
+    [RaisesException, CallWith=ScriptState] Promise<void> abort(
         optional any reason);
-    [RaisesException, CallWith=ScriptState, NotEnumerable] Promise<void> close();
-    [RaisesException, CallWith=ScriptState, NotEnumerable] WritableStreamDefaultWriter getWriter();
+    [RaisesException, CallWith=ScriptState] Promise<void> close();
+    [RaisesException, CallWith=ScriptState] WritableStreamDefaultWriter getWriter();
 };
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_controller.idl b/third_party/blink/renderer/core/streams/writable_stream_default_controller.idl
index f301939..c7bc87a 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_default_controller.idl
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_controller.idl
@@ -6,5 +6,5 @@
 
 // https://streams.spec.whatwg.org/#ws-default-controller-class-definition
 interface WritableStreamDefaultController {
-    [CallWith=ScriptState, NotEnumerable] void error(optional any e);
+    [CallWith=ScriptState] void error(optional any e);
 };
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl b/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl
index 0b59cdf3..cafcd45 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl
@@ -9,17 +9,17 @@
     Exposed=(Window,Worker,Worklet)
 ] interface WritableStreamDefaultWriter {
     [CallWith=ScriptState, RaisesException] constructor(WritableStream stream);
-    [CallWith=ScriptState, NotEnumerable] readonly attribute Promise<void>
+    [CallWith=ScriptState] readonly attribute Promise<void>
         closed;
-    [RaisesException, CallWith=ScriptState, NotEnumerable] readonly attribute
+    [RaisesException, CallWith=ScriptState] readonly attribute
         any desiredSize;
-    [CallWith=ScriptState, NotEnumerable] readonly attribute Promise<void>
+    [CallWith=ScriptState] readonly attribute Promise<void>
         ready;
 
-    [CallWith=ScriptState, RaisesException, NotEnumerable] Promise<void> abort(
+    [CallWith=ScriptState, RaisesException] Promise<void> abort(
         optional any reason);
-    [CallWith=ScriptState, RaisesException, NotEnumerable] Promise<void> close();
+    [CallWith=ScriptState, RaisesException] Promise<void> close();
     [CallWith=ScriptState, NotEnumerable] void releaseLock();
-    [CallWith=ScriptState, RaisesException, NotEnumerable] Promise<void> write(
+    [CallWith=ScriptState, RaisesException] Promise<void> write(
         optional any chunk);
 };
diff --git a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5 b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
index f2eb0d3..13ed67e 100644
--- a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
+++ b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
@@ -220,7 +220,8 @@
         fields_to_diff: ["width", "min-width", "max-width", "height", "min-height",
                 "max-height", "VerticalAlignLength", "box-sizing", "align-content",
                 "align-items", "align-self", "justify-content", "justify-items",
-                "justify-self", "contain", "contain-intrinsic-size", "aspect-ratio"],
+                "justify-self", "contain", "contain-intrinsic-size", "aspect-ratio",
+                "overflow-clip-margin"],
         methods_to_diff: [
           {
             method: "VerticalAlign()",
@@ -379,7 +380,6 @@
     },
     {
         name: "UpdatePropertySpecificDifferencesNeedsRecomputeVisualOverflow",
-        fields_to_diff: ["overflow-clip-margin"],
         predicates_to_test: [
           {
             predicate: "a.BoxShadowDataEquivalent(b)",
diff --git a/third_party/blink/renderer/core/timing/performance_navigation.cc b/third_party/blink/renderer/core/timing/performance_navigation.cc
index 7dd856a..0344ca4 100644
--- a/third_party/blink/renderer/core/timing/performance_navigation.cc
+++ b/third_party/blink/renderer/core/timing/performance_navigation.cc
@@ -32,25 +32,20 @@
 
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/core/loader/frame_loader_types.h"
 
 // Legacy support for NT1(https://www.w3.org/TR/navigation-timing/).
 namespace blink {
 
-PerformanceNavigation::PerformanceNavigation(LocalFrame* frame)
-    : ExecutionContextClient(frame) {}
+PerformanceNavigation::PerformanceNavigation(ExecutionContext* context)
+    : ExecutionContextClient(context) {}
 
 uint8_t PerformanceNavigation::type() const {
-  if (!GetFrame())
+  if (!DomWindow())
     return kTypeNavigate;
 
-  DocumentLoader* document_loader = GetFrame()->Loader().GetDocumentLoader();
-  if (!document_loader)
-    return kTypeNavigate;
-
-  switch (document_loader->GetNavigationType()) {
+  switch (DomWindow()->document()->Loader()->GetNavigationType()) {
     case kWebNavigationTypeReload:
       return kTypeReload;
     case kWebNavigationTypeBackForward:
@@ -61,14 +56,11 @@
 }
 
 uint16_t PerformanceNavigation::redirectCount() const {
-  if (!GetFrame())
+  if (!DomWindow())
     return 0;
 
-  DocumentLoader* loader = GetFrame()->Loader().GetDocumentLoader();
-  if (!loader)
-    return 0;
-
-  const DocumentLoadTiming& timing = loader->GetTiming();
+  const DocumentLoadTiming& timing =
+      DomWindow()->document()->Loader()->GetTiming();
   if (timing.HasCrossOriginRedirect())
     return 0;
 
diff --git a/third_party/blink/renderer/core/timing/performance_navigation.h b/third_party/blink/renderer/core/timing/performance_navigation.h
index 9ad260b9..1ddafc4 100644
--- a/third_party/blink/renderer/core/timing/performance_navigation.h
+++ b/third_party/blink/renderer/core/timing/performance_navigation.h
@@ -38,7 +38,6 @@
 
 namespace blink {
 
-class LocalFrame;
 class ScriptState;
 class ScriptValue;
 
@@ -48,7 +47,7 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit PerformanceNavigation(LocalFrame*);
+  explicit PerformanceNavigation(ExecutionContext*);
 
   enum PerformanceNavigationType {
     kTypeNavigate,
diff --git a/third_party/blink/renderer/core/timing/performance_navigation_timing.cc b/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
index 10b27f5..de84bfd 100644
--- a/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
+++ b/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
@@ -8,7 +8,6 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/document_timing.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/loader/document_load_timing.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
 #include "third_party/blink/renderer/core/performance_entry_names.h"
@@ -47,7 +46,7 @@
 }  // namespace
 
 PerformanceNavigationTiming::PerformanceNavigationTiming(
-    LocalFrame* frame,
+    LocalDOMWindow* window,
     ResourceTimingInfo* info,
     base::TimeTicks time_origin,
     HeapVector<Member<PerformanceServerTiming>> server_timing)
@@ -56,13 +55,12 @@
                      info->FinalResponse().CurrentRequestUrl().GetString())
                : g_empty_atom,
           time_origin,
-          SecurityOrigin::IsSecure(frame->GetDocument()->Url()),
+          SecurityOrigin::IsSecure(window->Url()),
           std::move(server_timing),
-          frame->DomWindow()),
-      ExecutionContextClient(frame),
+          window),
+      ExecutionContextClient(window),
       resource_timing_info_(info) {
-  DCHECK(frame);
-  DCHECK(frame->GetDocument());
+  DCHECK(window);
   DCHECK(info);
 }
 
@@ -90,19 +88,11 @@
 }
 
 DocumentLoader* PerformanceNavigationTiming::GetDocumentLoader() const {
-  if (!GetFrame())
-    return nullptr;
-  return GetFrame()->Loader().GetDocumentLoader();
+  return DomWindow() ? DomWindow()->document()->Loader() : nullptr;
 }
 
 const DocumentTiming* PerformanceNavigationTiming::GetDocumentTiming() const {
-  if (!GetFrame())
-    return nullptr;
-  Document* document = GetFrame()->GetDocument();
-  if (!document)
-    return nullptr;
-
-  return &document->GetTiming();
+  return DomWindow() ? &DomWindow()->document()->GetTiming() : nullptr;
 }
 
 ResourceLoadTiming* PerformanceNavigationTiming::GetResourceLoadTiming() const {
@@ -152,15 +142,12 @@
 }
 
 bool PerformanceNavigationTiming::GetAllowRedirectDetails() const {
-  blink::ExecutionContext* context =
-      GetFrame() ? GetFrame()->DomWindow() : nullptr;
-  const blink::SecurityOrigin* security_origin = nullptr;
-  if (context)
-    security_origin = context->GetSecurityOrigin();
-  if (!security_origin)
+  if (!GetExecutionContext())
     return false;
   // TODO(sunjian): Think about how to make this flag deterministic.
   // crbug/693183.
+  const blink::SecurityOrigin* security_origin =
+      GetExecutionContext()->GetSecurityOrigin();
   return AllowNavigationTimingRedirect(resource_timing_info_->RedirectChain(),
                                        resource_timing_info_->FinalResponse(),
                                        *security_origin);
@@ -250,10 +237,10 @@
 }
 
 AtomicString PerformanceNavigationTiming::type() const {
-  DocumentLoader* loader = GetDocumentLoader();
-  if (GetFrame() && loader)
-    return GetNavigationType(loader->GetNavigationType(),
-                             GetFrame()->GetDocument());
+  if (DomWindow()) {
+    return GetNavigationType(GetDocumentLoader()->GetNavigationType(),
+                             DomWindow()->document());
+  }
   return "navigate";
 }
 
diff --git a/third_party/blink/renderer/core/timing/performance_navigation_timing.h b/third_party/blink/renderer/core/timing/performance_navigation_timing.h
index 11d1e60..c566ccb 100644
--- a/third_party/blink/renderer/core/timing/performance_navigation_timing.h
+++ b/third_party/blink/renderer/core/timing/performance_navigation_timing.h
@@ -19,7 +19,7 @@
 class DocumentTiming;
 class DocumentLoader;
 class DocumentLoadTiming;
-class LocalFrame;
+class LocalDOMWindow;
 class ExecutionContext;
 class ResourceTimingInfo;
 class ResourceLoadTiming;
@@ -31,7 +31,7 @@
   friend class PerformanceNavigationTimingTest;
 
  public:
-  PerformanceNavigationTiming(LocalFrame*,
+  PerformanceNavigationTiming(LocalDOMWindow*,
                               ResourceTimingInfo*,
                               base::TimeTicks time_origin,
                               HeapVector<Member<PerformanceServerTiming>>);
diff --git a/third_party/blink/renderer/core/timing/performance_timing.cc b/third_party/blink/renderer/core/timing/performance_timing.cc
index aecd922..87fa82d 100644
--- a/third_party/blink/renderer/core/timing/performance_timing.cc
+++ b/third_party/blink/renderer/core/timing/performance_timing.cc
@@ -35,11 +35,9 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/document_parser_timing.h"
 #include "third_party/blink/renderer/core/dom/document_timing.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
 #include "third_party/blink/renderer/core/loader/document_load_timing.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/core/loader/frame_loader.h"
 #include "third_party/blink/renderer/core/loader/interactive_detector.h"
 #include "third_party/blink/renderer/core/paint/image_paint_timing_detector.h"
 #include "third_party/blink/renderer/core/paint/paint_timing.h"
@@ -62,8 +60,8 @@
   return static_cast<uint64_t>(clamped_seconds * 1000.0);
 }
 
-PerformanceTiming::PerformanceTiming(LocalFrame* frame)
-    : ExecutionContextClient(frame) {}
+PerformanceTiming::PerformanceTiming(ExecutionContext* context)
+    : ExecutionContextClient(context) {}
 
 uint64_t PerformanceTiming::navigationStart() const {
   DocumentLoadTiming* timing = GetDocumentLoadTiming();
@@ -616,43 +614,26 @@
 }
 
 DocumentLoader* PerformanceTiming::GetDocumentLoader() const {
-  if (!GetFrame())
-    return nullptr;
-
-  return GetFrame()->Loader().GetDocumentLoader();
+  return DomWindow() ? DomWindow()->GetFrame()->Loader().GetDocumentLoader()
+                     : nullptr;
 }
 
 const DocumentTiming* PerformanceTiming::GetDocumentTiming() const {
-  if (!GetFrame())
+  if (!DomWindow() || !DomWindow()->document())
     return nullptr;
-
-  Document* document = GetFrame()->GetDocument();
-  if (!document)
-    return nullptr;
-
-  return &document->GetTiming();
+  return &DomWindow()->document()->GetTiming();
 }
 
 const PaintTiming* PerformanceTiming::GetPaintTiming() const {
-  if (!GetFrame())
+  if (!DomWindow() || !DomWindow()->document())
     return nullptr;
-
-  Document* document = GetFrame()->GetDocument();
-  if (!document)
-    return nullptr;
-
-  return &PaintTiming::From(*document);
+  return &PaintTiming::From(*DomWindow()->document());
 }
 
 const DocumentParserTiming* PerformanceTiming::GetDocumentParserTiming() const {
-  if (!GetFrame())
+  if (!DomWindow() || !DomWindow()->document())
     return nullptr;
-
-  Document* document = GetFrame()->GetDocument();
-  if (!document)
-    return nullptr;
-
-  return &DocumentParserTiming::From(*document);
+  return &DocumentParserTiming::From(*DomWindow()->document());
 }
 
 DocumentLoadTiming* PerformanceTiming::GetDocumentLoadTiming() const {
@@ -672,25 +653,15 @@
 }
 
 InteractiveDetector* PerformanceTiming::GetInteractiveDetector() const {
-  if (!GetFrame())
+  if (!DomWindow() || !DomWindow()->document())
     return nullptr;
-
-  Document* document = GetFrame()->GetDocument();
-  if (!document)
-    return nullptr;
-
-  return InteractiveDetector::From(*document);
+  return InteractiveDetector::From(*DomWindow()->document());
 }
 
 PaintTimingDetector* PerformanceTiming::GetPaintTimingDetector() const {
-  if (!GetFrame())
+  if (!DomWindow())
     return nullptr;
-
-  LocalFrameView* view = GetFrame()->View();
-  if (!view)
-    return nullptr;
-
-  return &view->GetPaintTimingDetector();
+  return &DomWindow()->GetFrame()->View()->GetPaintTimingDetector();
 }
 
 base::Optional<base::TimeDelta>
diff --git a/third_party/blink/renderer/core/timing/performance_timing.h b/third_party/blink/renderer/core/timing/performance_timing.h
index ff8b8be..13fbc09 100644
--- a/third_party/blink/renderer/core/timing/performance_timing.h
+++ b/third_party/blink/renderer/core/timing/performance_timing.h
@@ -46,7 +46,6 @@
 class DocumentParserTiming;
 class DocumentTiming;
 class InteractiveDetector;
-class LocalFrame;
 class PaintTiming;
 class PaintTimingDetector;
 class ResourceLoadTiming;
@@ -68,7 +67,7 @@
   using BackForwardCacheRestoreTimings =
       WTF::Vector<BackForwardCacheRestoreTiming>;
 
-  explicit PerformanceTiming(LocalFrame*);
+  explicit PerformanceTiming(ExecutionContext*);
 
   uint64_t navigationStart() const;
   uint64_t inputStart() const;
diff --git a/third_party/blink/renderer/core/timing/window_performance.cc b/third_party/blink/renderer/core/timing/window_performance.cc
index a43d98f0..bf39c37 100644
--- a/third_party/blink/renderer/core/timing/window_performance.cc
+++ b/third_party/blink/renderer/core/timing/window_performance.cc
@@ -153,10 +153,10 @@
     : Performance(ToTimeOrigin(window),
                   window->GetTaskRunner(TaskType::kPerformanceTimeline)),
       ExecutionContextClient(window),
-      PageVisibilityObserver(GetFrame()->GetPage()) {
-  DCHECK(GetFrame());
-  DCHECK(GetFrame()->GetPerformanceMonitor());
-  GetFrame()->GetPerformanceMonitor()->Subscribe(
+      PageVisibilityObserver(window->GetFrame()->GetPage()) {
+  DCHECK(window);
+  DCHECK(window->GetFrame()->GetPerformanceMonitor());
+  window->GetFrame()->GetPerformanceMonitor()->Subscribe(
       PerformanceMonitor::kLongTask, kLongTaskObserverThreshold, this);
   if (RuntimeEnabledFeatures::VisibilityStateEntryEnabled()) {
     DCHECK(GetPage());
@@ -167,21 +167,19 @@
 WindowPerformance::~WindowPerformance() = default;
 
 ExecutionContext* WindowPerformance::GetExecutionContext() const {
-  if (!GetFrame())
-    return nullptr;
-  return GetFrame()->DomWindow();
+  return ExecutionContextClient::GetExecutionContext();
 }
 
 PerformanceTiming* WindowPerformance::timing() const {
   if (!timing_)
-    timing_ = MakeGarbageCollected<PerformanceTiming>(GetFrame());
+    timing_ = MakeGarbageCollected<PerformanceTiming>(DomWindow());
 
   return timing_.Get();
 }
 
 PerformanceNavigation* WindowPerformance::navigation() const {
   if (!navigation_)
-    navigation_ = MakeGarbageCollected<PerformanceNavigation>(GetFrame());
+    navigation_ = MakeGarbageCollected<PerformanceNavigation>(DomWindow());
 
   return navigation_.Get();
 }
@@ -200,11 +198,9 @@
 
 PerformanceNavigationTiming*
 WindowPerformance::CreateNavigationTimingInstance() {
-  if (!GetFrame())
+  if (!DomWindow())
     return nullptr;
-  DocumentLoader* document_loader = GetFrame()->Loader().GetDocumentLoader();
-  if (!document_loader)
-    return nullptr;
+  DocumentLoader* document_loader = DomWindow()->document()->Loader();
   ResourceTimingInfo* info = document_loader->GetNavigationTimingInfo();
   if (!info)
     return nullptr;
@@ -214,7 +210,7 @@
     document_loader->CountUse(WebFeature::kPerformanceServerTiming);
 
   return MakeGarbageCollected<PerformanceNavigationTiming>(
-      GetFrame(), info, time_origin_, std::move(server_timing));
+      DomWindow(), info, time_origin_, std::move(server_timing));
 }
 
 void WindowPerformance::BuildJSONValue(V8ObjectBuilder& builder) const {
@@ -309,11 +305,11 @@
                                        base::TimeTicks end_time,
                                        ExecutionContext* task_context,
                                        bool has_multiple_contexts) {
-  if (!GetFrame())
+  if (!DomWindow())
     return;
   std::pair<AtomicString, DOMWindow*> attribution =
       WindowPerformance::SanitizedAttribution(
-          task_context, has_multiple_contexts, GetFrame());
+          task_context, has_multiple_contexts, DomWindow()->GetFrame());
   DOMWindow* culprit_dom_window = attribution.second;
   if (!culprit_dom_window || !culprit_dom_window->GetFrame() ||
       !culprit_dom_window->GetFrame()->DeprecatedLocalOwner()) {
@@ -339,7 +335,7 @@
   DCHECK(!processing_start.is_null());
   DCHECK(!processing_end.is_null());
   DCHECK_GE(processing_end, processing_start);
-  if (!GetFrame())
+  if (!DomWindow())
     return;
 
   if (!event_counts_)
@@ -366,8 +362,8 @@
     should_queue_swap_promise = frame_index_ > last_registered_frame_index_;
   }
   if (should_queue_swap_promise) {
-    GetFrame()->GetChromeClient().NotifySwapTime(
-        *GetFrame(),
+    DomWindow()->GetFrame()->GetChromeClient().NotifySwapTime(
+        *DomWindow()->GetFrame(),
         CrossThreadBindOnce(&WindowPerformance::ReportEventTimings,
                             WrapCrossThreadWeakPersistent(this), frame_index_));
     last_registered_frame_index_ = frame_index_;
diff --git a/third_party/blink/renderer/core/timing/window_performance_test.cc b/third_party/blink/renderer/core/timing/window_performance_test.cc
index 2d020611..070c3f60 100644
--- a/third_party/blink/renderer/core/timing/window_performance_test.cc
+++ b/third_party/blink/renderer/core/timing/window_performance_test.cc
@@ -177,8 +177,8 @@
   ASSERT_TRUE(document_loader);
   document_loader->GetTiming().SetNavigationStart(base::TimeTicks::Now());
 
-  EXPECT_EQ(&page_holder->GetFrame(), perf->GetFrame());
-  EXPECT_EQ(&page_holder->GetFrame(), timing->GetFrame());
+  EXPECT_EQ(page_holder->GetFrame().DomWindow(), perf->DomWindow());
+  EXPECT_EQ(page_holder->GetFrame().DomWindow(), timing->DomWindow());
   auto navigation_start = timing->navigationStart();
   EXPECT_NE(0U, navigation_start);
 
@@ -190,8 +190,8 @@
   EXPECT_EQ(perf, DOMWindowPerformance::performance(
                       *page_holder->GetFrame().DomWindow()));
   EXPECT_EQ(timing, perf->timing());
-  EXPECT_EQ(&page_holder->GetFrame(), perf->GetFrame());
-  EXPECT_EQ(&page_holder->GetFrame(), timing->GetFrame());
+  EXPECT_EQ(page_holder->GetFrame().DomWindow(), perf->DomWindow());
+  EXPECT_EQ(page_holder->GetFrame().DomWindow(), timing->DomWindow());
   EXPECT_LE(navigation_start, timing->navigationStart());
 }
 
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 06005f76..ddb3eaf4 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -459,6 +459,7 @@
     "bindings/v8_dom_wrapper.h",
     "bindings/v8_global_value_map.h",
     "bindings/v8_interface_bridge.h",
+    "bindings/v8_interface_bridge_base.h",
     "bindings/v8_object_constructor.cc",
     "bindings/v8_object_constructor.h",
     "bindings/v8_per_context_data.cc",
diff --git a/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.cc b/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.cc
index ef308c8..8c2c5db 100644
--- a/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.cc
+++ b/third_party/blink/renderer/platform/bindings/v8_dom_wrapper.cc
@@ -62,7 +62,8 @@
     // V8PerContextData::createWrapperFromCache, though there is no need to
     // cache resulting objects or their constructors.
     const DOMWrapperWorld& world = DOMWrapperWorld::World(scope.GetContext());
-    wrapper = type->DomTemplate(isolate, world)
+    wrapper = type->GetV8ClassTemplate(isolate, world)
+                  .As<v8::FunctionTemplate>()
                   ->InstanceTemplate()
                   ->NewInstance(scope.GetContext())
                   .ToLocalChecked();
diff --git a/third_party/blink/renderer/platform/bindings/v8_interface_bridge.h b/third_party/blink/renderer/platform/bindings/v8_interface_bridge.h
index ece99f6..6e99f424 100644
--- a/third_party/blink/renderer/platform/bindings/v8_interface_bridge.h
+++ b/third_party/blink/renderer/platform/bindings/v8_interface_bridge.h
@@ -6,99 +6,13 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_V8_INTERFACE_BRIDGE_H_
 
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/bindings/v8_interface_bridge_base.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
-#include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "v8/include/v8.h"
 
 namespace blink {
 
-class DOMWrapperWorld;
-
 namespace bindings {
 
-// The common base class of code-generated V8-Blink bridge class of IDL
-// interfaces and namespaces.
-class PLATFORM_EXPORT V8InterfaceBridgeBase {
-  STATIC_ONLY(V8InterfaceBridgeBase);
-
- public:
-  // Selects properties to be installed according to origin trial features.
-  //
-  // There are two usages.
-  // 1) At the first call of V8T::InstallContextDependentProperties, install
-  //   (a) properties that are not associated to origin trial features (e.g.
-  //   secure contexts) plus (b) properties that are associated to origin trial
-  //   features and are already enabled by the moment of the call.
-  // 2) On 2nd+ call of V8T::InstallContextDependentProperties (when an origin
-  //   trial feature gets enabled later on), install only (c) properties that
-  //   are associated to the origin trial feature that has got enabled.
-  //
-  // FeatureSelector() is used for usage 1) and
-  // FeatureSelector(feature) is used for usage 2).
-  class FeatureSelector final {
-   public:
-    // Selects all properties not associated to any origin trial feature and
-    // properties associated with the origin trial features that are already
-    // enabled.
-    FeatureSelector() : does_select_all_(true) {}
-    // Selects only the properties that are associated to the given origin
-    // trial feature.
-    FeatureSelector(OriginTrialFeature feature) : selector_(feature) {}
-    FeatureSelector(const FeatureSelector&) = default;
-    FeatureSelector(FeatureSelector&&) = default;
-    ~FeatureSelector() = default;
-
-    FeatureSelector& operator=(const FeatureSelector&) = default;
-    FeatureSelector& operator=(FeatureSelector&&) = default;
-
-    // Returns true if all properties that are associated with the features
-    // enabled at this moment should be installed.
-    bool IsAll() const { return does_select_all_; }
-
-    // Returns true if properties should be installed.  Arguments |featureN|
-    // represent the origin trial features to which the properties are
-    // associated.
-    bool IsAnyOf(OriginTrialFeature feature1) const {
-      return selector_ == feature1;
-    }
-    bool IsAnyOf(OriginTrialFeature feature1,
-                 OriginTrialFeature feature2) const {
-      return selector_ == feature1 || selector_ == feature2;
-    }
-
-   private:
-    bool does_select_all_ = false;
-    OriginTrialFeature selector_ = OriginTrialFeature::kNonExisting;
-  };
-
-  using InstallInterfaceTemplateFuncType =
-      void (*)(v8::Isolate* isolate,
-               const DOMWrapperWorld& world,
-               v8::Local<v8::FunctionTemplate> interface_template);
-  using InstallUnconditionalPropertiesFuncType =
-      void (*)(v8::Isolate* isolate,
-               const DOMWrapperWorld& world,
-               v8::Local<v8::ObjectTemplate> instance_template,
-               v8::Local<v8::ObjectTemplate> prototype_template,
-               v8::Local<v8::FunctionTemplate> interface_template);
-  using InstallContextIndependentPropertiesFuncType =
-      void (*)(v8::Isolate* isolate,
-               const DOMWrapperWorld& world,
-               v8::Local<v8::ObjectTemplate> instance_template,
-               v8::Local<v8::ObjectTemplate> prototype_template,
-               v8::Local<v8::FunctionTemplate> interface_template);
-  using InstallContextDependentPropertiesFuncType =
-      void (*)(v8::Local<v8::Context> context,
-               const DOMWrapperWorld& world,
-               v8::Local<v8::Object> instance_object,
-               v8::Local<v8::Object> prototype_object,
-               v8::Local<v8::Function> interface_object,
-               v8::Local<v8::FunctionTemplate> interface_template,
-               FeatureSelector feature_selector);
-};
-
 template <class V8T, class T>
 class V8InterfaceBridge : public V8InterfaceBridgeBase {
  public:
diff --git a/third_party/blink/renderer/platform/bindings/v8_interface_bridge_base.h b/third_party/blink/renderer/platform/bindings/v8_interface_bridge_base.h
new file mode 100644
index 0000000..3c01116
--- /dev/null
+++ b/third_party/blink/renderer/platform/bindings/v8_interface_bridge_base.h
@@ -0,0 +1,104 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_V8_INTERFACE_BRIDGE_BASE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_V8_INTERFACE_BRIDGE_BASE_H_
+
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+class DOMWrapperWorld;
+
+namespace bindings {
+
+// The common base class of code-generated V8-Blink bridge class of IDL
+// interfaces and namespaces.
+class PLATFORM_EXPORT V8InterfaceBridgeBase {
+  STATIC_ONLY(V8InterfaceBridgeBase);
+
+ public:
+  // Selects properties to be installed according to origin trial features.
+  //
+  // There are two usages.
+  // 1) At the first call of V8T::InstallContextDependentProperties, install
+  //   (a) properties that are not associated to origin trial features (e.g.
+  //   secure contexts) plus (b) properties that are associated to origin trial
+  //   features and are already enabled by the moment of the call.
+  // 2) On 2nd+ call of V8T::InstallContextDependentProperties (when an origin
+  //   trial feature gets enabled later on), install only (c) properties that
+  //   are associated to the origin trial feature that has got enabled.
+  //
+  // FeatureSelector() is used for usage 1) and
+  // FeatureSelector(feature) is used for usage 2).
+  class FeatureSelector final {
+   public:
+    // Selects all properties not associated to any origin trial feature and
+    // properties associated with the origin trial features that are already
+    // enabled.
+    FeatureSelector() : does_select_all_(true) {}
+    // Selects only the properties that are associated to the given origin
+    // trial feature.
+    explicit FeatureSelector(OriginTrialFeature feature) : selector_(feature) {}
+    FeatureSelector(const FeatureSelector&) = default;
+    FeatureSelector(FeatureSelector&&) = default;
+    ~FeatureSelector() = default;
+
+    FeatureSelector& operator=(const FeatureSelector&) = default;
+    FeatureSelector& operator=(FeatureSelector&&) = default;
+
+    // Returns true if all properties that are associated with the features
+    // enabled at this moment should be installed.
+    bool IsAll() const { return does_select_all_; }
+
+    // Returns true if properties should be installed.  Arguments |featureN|
+    // represent the origin trial features to which the properties are
+    // associated.
+    bool IsAnyOf(OriginTrialFeature feature1) const {
+      return selector_ == feature1;
+    }
+    bool IsAnyOf(OriginTrialFeature feature1,
+                 OriginTrialFeature feature2) const {
+      return selector_ == feature1 || selector_ == feature2;
+    }
+
+   private:
+    bool does_select_all_ = false;
+    OriginTrialFeature selector_ = OriginTrialFeature::kNonExisting;
+  };
+
+  using InstallInterfaceTemplateFuncType =
+      void (*)(v8::Isolate* isolate,
+               const DOMWrapperWorld& world,
+               v8::Local<v8::Template> interface_template);
+  using InstallUnconditionalPropertiesFuncType =
+      void (*)(v8::Isolate* isolate,
+               const DOMWrapperWorld& world,
+               v8::Local<v8::Template> instance_template,
+               v8::Local<v8::Template> prototype_template,
+               v8::Local<v8::Template> interface_template);
+  using InstallContextIndependentPropertiesFuncType =
+      void (*)(v8::Isolate* isolate,
+               const DOMWrapperWorld& world,
+               v8::Local<v8::Template> instance_template,
+               v8::Local<v8::Template> prototype_template,
+               v8::Local<v8::Template> interface_template);
+  using InstallContextDependentPropertiesFuncType =
+      void (*)(v8::Local<v8::Context> context,
+               const DOMWrapperWorld& world,
+               v8::Local<v8::Object> instance_object,
+               v8::Local<v8::Object> prototype_object,
+               v8::Local<v8::Object> interface_object,
+               v8::Local<v8::Template> interface_template,
+               FeatureSelector feature_selector);
+};
+
+}  // namespace bindings
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_V8_INTERFACE_BRIDGE_BASE_H_
diff --git a/third_party/blink/renderer/platform/bindings/v8_object_constructor.cc b/third_party/blink/renderer/platform/bindings/v8_object_constructor.cc
index ac84b104..196548f9 100644
--- a/third_party/blink/renderer/platform/bindings/v8_object_constructor.cc
+++ b/third_party/blink/renderer/platform/bindings/v8_object_constructor.cc
@@ -73,11 +73,8 @@
     v8::Isolate* isolate,
     v8::Local<v8::Function> parent_interface,
     CreationMode creation_mode) {
-  // We shouldn't reach this point for the types that are implemented in v8 such
-  // as typed arrays and hence don't have DomTemplateFunction.
-  DCHECK(type->dom_template_function);
   v8::Local<v8::FunctionTemplate> interface_template =
-      type->DomTemplate(isolate, world);
+      type->GetV8ClassTemplate(isolate, world).As<v8::FunctionTemplate>();
   // Getting the function might fail if we're running out of stack or memory.
   v8::Local<v8::Function> interface_object;
   bool get_interface_object =
diff --git a/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc b/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc
index 2a94906a..15d7102 100644
--- a/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc
+++ b/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc
@@ -6,8 +6,8 @@
 
 #include "third_party/blink/renderer/platform/bindings/custom_wrappable.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
+#include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 
 namespace blink {
 
@@ -16,6 +16,39 @@
               "offset of WrapperTypeInfo.ginEmbedder must be the same as "
               "gin::WrapperInfo.embedder");
 
+v8::Local<v8::Template> WrapperTypeInfo::GetV8ClassTemplate(
+    v8::Isolate* isolate,
+    const DOMWrapperWorld& world) const {
+  V8PerIsolateData* per_isolate_data = V8PerIsolateData::From(isolate);
+  v8::Local<v8::Template> v8_template =
+      per_isolate_data->FindV8Template(world, this);
+  if (!v8_template.IsEmpty())
+    return v8_template;
+
+  switch (idl_definition_kind) {
+    case kIdlInterface:
+      v8_template = v8::FunctionTemplate::New(
+          isolate, V8ObjectConstructor::IsValidConstructorMode);
+      break;
+    case kIdlNamespace:
+      v8_template = v8::ObjectTemplate::New(isolate);
+      break;
+    case kIdlCallbackInterface:
+      v8_template = v8::FunctionTemplate::New(
+          isolate, V8ObjectConstructor::IsValidConstructorMode);
+      break;
+    case kCustomWrappableKind:
+      v8_template = v8::FunctionTemplate::New(isolate);
+      break;
+    default:
+      NOTREACHED();
+  }
+  install_interface_template_func(isolate, world, v8_template);
+
+  per_isolate_data->AddV8Template(world, this, v8_template);
+  return v8_template;
+}
+
 void WrapperTypeInfo::Trace(Visitor* visitor, const void* impl) const {
   switch (wrapper_class_id) {
     case WrapperTypeInfo::kNodeClassId:
diff --git a/third_party/blink/renderer/platform/bindings/wrapper_type_info.h b/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
index 3ad83fdb..e544f77 100644
--- a/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
+++ b/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
@@ -32,6 +32,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_WRAPPER_TYPE_INFO_H_
 
 #include "gin/public/wrapper_info.h"
+#include "third_party/blink/renderer/platform/bindings/v8_interface_bridge_base.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
@@ -39,16 +40,11 @@
 
 namespace blink {
 
-class ActiveScriptWrappableBase;
 class CustomWrappable;
 class DOMWrapperWorld;
 class ScriptWrappable;
 class Visitor;
 
-ScriptWrappable* ToScriptWrappable(
-    const v8::PersistentBase<v8::Object>& wrapper);
-ScriptWrappable* ToScriptWrappable(v8::Local<v8::Object> wrapper);
-
 static const int kV8DOMWrapperTypeIndex =
     static_cast<int>(gin::kWrapperInfoIndex);
 static const int kV8DOMWrapperObjectIndex =
@@ -59,27 +55,11 @@
 // corresponding Index constant exists for it.
 static const int kV8PrototypeInternalFieldcount = 1;
 
-typedef v8::Local<v8::FunctionTemplate> (
-    *DomTemplateFunction)(v8::Isolate*, const DOMWrapperWorld&);
-typedef ActiveScriptWrappableBase* (*ToActiveScriptWrappableFunction)(
-    v8::Local<v8::Object>);
-typedef void (*ResolveWrapperReachabilityFunction)(
-    v8::Isolate*,
-    ScriptWrappable*,
-    const v8::Persistent<v8::Object>&);
-typedef void (*InstallConditionalFeaturesFunction)(
-    v8::Local<v8::Context>,
-    const DOMWrapperWorld&,
-    v8::Local<v8::Object>,
-    v8::Local<v8::Object>,
-    v8::Local<v8::Function>,
-    v8::Local<v8::FunctionTemplate>);
-
 // This struct provides a way to store a bunch of information that is helpful
 // when unwrapping v8 objects. Each v8 bindings class has exactly one static
 // WrapperTypeInfo member, so comparing pointers is a safe way to determine if
 // types match.
-struct WrapperTypeInfo {
+struct PLATFORM_EXPORT WrapperTypeInfo final {
   DISALLOW_NEW();
 
   enum WrapperTypePrototype {
@@ -98,6 +78,13 @@
     kInheritFromActiveScriptWrappable,
   };
 
+  enum IdlDefinitionKind {
+    kIdlInterface,
+    kIdlNamespace,
+    kIdlCallbackInterface,
+    kCustomWrappableKind,
+  };
+
   static const WrapperTypeInfo* Unwrap(v8::Local<v8::Value> type_info_wrapper) {
     return reinterpret_cast<const WrapperTypeInfo*>(
         v8::External::Cast(*type_info_wrapper)->Value());
@@ -115,32 +102,35 @@
     return false;
   }
 
-  void ConfigureWrapper(v8::PersistentBase<v8::Object>* wrapper) const {
-    wrapper->SetWrapperClassId(wrapper_class_id);
-  }
-
   void ConfigureWrapper(v8::TracedReference<v8::Object>* wrapper) const {
     wrapper->SetWrapperClassId(wrapper_class_id);
   }
 
-  v8::Local<v8::FunctionTemplate> DomTemplate(
+  // Returns a v8::Template of interface object, namespace object, or the
+  // counterpart of the IDL definition.
+  //
+  // - kIdlInterface: v8::FunctionTemplate of interface object
+  // - kIdlNamespace: v8::ObjectTemplate of namespace object
+  // - kIdlCallbackInterface: v8::FunctionTemplate of legacy callback interface
+  //       object
+  // - kCustomWrappableKind: v8::FunctionTemplate
+  v8::Local<v8::Template> GetV8ClassTemplate(
       v8::Isolate* isolate,
-      const DOMWrapperWorld& world) const {
-    return dom_template_function(isolate, world);
-  }
+      const DOMWrapperWorld& world) const;
 
   void InstallConditionalFeatures(
       v8::Local<v8::Context> context,
       const DOMWrapperWorld& world,
       v8::Local<v8::Object> instance_object,
       v8::Local<v8::Object> prototype_object,
-      v8::Local<v8::Function> interface_object,
-      v8::Local<v8::FunctionTemplate> interface_template) const {
-    if (install_conditional_features_function) {
-      install_conditional_features_function(context, world, instance_object,
-                                            prototype_object, interface_object,
-                                            interface_template);
-    }
+      v8::Local<v8::Object> interface_object,
+      v8::Local<v8::Template> interface_template) const {
+    if (!install_context_dependent_props_func)
+      return;
+
+    install_context_dependent_props_func(
+        context, world, instance_object, prototype_object, interface_object,
+        interface_template, bindings::V8InterfaceBridgeBase::FeatureSelector());
   }
 
   bool IsActiveScriptWrappable() const {
@@ -150,30 +140,26 @@
 
   // Garbage collection support for when the type depends the WrapperTypeInfo
   // object.
-  PLATFORM_EXPORT void Trace(Visitor*, const void*) const;
+  void Trace(Visitor*, const void*) const;
 
   // This field must be the first member of the struct WrapperTypeInfo.
   // See also static_assert() in .cpp file.
   const gin::GinEmbedder gin_embedder;
 
-  DomTemplateFunction dom_template_function;
-  InstallConditionalFeaturesFunction install_conditional_features_function;
-  const char* const interface_name;
+  bindings::V8InterfaceBridgeBase::InstallInterfaceTemplateFuncType
+      install_interface_template_func;
+  bindings::V8InterfaceBridgeBase::InstallContextDependentPropertiesFuncType
+      install_context_dependent_props_func;
+  const char* interface_name;
   const WrapperTypeInfo* parent_class;
-  const unsigned wrapper_type_prototype : 2;  // WrapperTypePrototype
-  const unsigned wrapper_class_id : 2;        // WrapperClassId
-  const unsigned  // ActiveScriptWrappableInheritance
+  unsigned wrapper_type_prototype : 2;  // WrapperTypePrototype
+  unsigned wrapper_class_id : 2;        // WrapperClassId
+  unsigned                              // ActiveScriptWrappableInheritance
       active_script_wrappable_inheritance : 1;
+  unsigned idl_definition_kind : 2;  // IdlDefinitionKind
 };
 
 template <typename T, int offset>
-inline T* GetInternalField(const v8::PersistentBase<v8::Object>& persistent) {
-  DCHECK_LT(offset, v8::Object::InternalFieldCount(persistent));
-  return reinterpret_cast<T*>(
-      v8::Object::GetAlignedPointerFromInternalField(persistent, offset));
-}
-
-template <typename T, int offset>
 inline T* GetInternalField(const v8::TracedReference<v8::Object>& global) {
   DCHECK_LT(offset, v8::Object::InternalFieldCount(global));
   return reinterpret_cast<T*>(
@@ -197,11 +183,6 @@
 // The return value can be null if |wrapper| is a global proxy, which points to
 // nothing while a navigation.
 inline ScriptWrappable* ToScriptWrappable(
-    const v8::PersistentBase<v8::Object>& wrapper) {
-  return GetInternalField<ScriptWrappable, kV8DOMWrapperObjectIndex>(wrapper);
-}
-
-inline ScriptWrappable* ToScriptWrappable(
     const v8::TracedReference<v8::Object>& wrapper) {
   return GetInternalField<ScriptWrappable, kV8DOMWrapperObjectIndex>(wrapper);
 }
@@ -214,19 +195,10 @@
   return GetInternalField<ScriptWrappable, kV8DOMWrapperObjectIndex>(wrapper);
 }
 
-inline CustomWrappable* ToCustomWrappable(
-    const v8::PersistentBase<v8::Object>& wrapper) {
-  return GetInternalField<CustomWrappable, kV8DOMWrapperObjectIndex>(wrapper);
-}
-
 inline CustomWrappable* ToCustomWrappable(v8::Local<v8::Object> wrapper) {
   return GetInternalField<CustomWrappable, kV8DOMWrapperObjectIndex>(wrapper);
 }
 
-inline void* ToUntypedWrappable(const v8::PersistentBase<v8::Object>& wrapper) {
-  return GetInternalField<void, kV8DOMWrapperObjectIndex>(wrapper);
-}
-
 inline void* ToUntypedWrappable(
     const v8::TracedReference<v8::Object>& wrapper) {
   return GetInternalField<void, kV8DOMWrapperObjectIndex>(wrapper);
@@ -237,11 +209,6 @@
 }
 
 inline const WrapperTypeInfo* ToWrapperTypeInfo(
-    const v8::PersistentBase<v8::Object>& wrapper) {
-  return GetInternalField<WrapperTypeInfo, kV8DOMWrapperTypeIndex>(wrapper);
-}
-
-inline const WrapperTypeInfo* ToWrapperTypeInfo(
     const v8::TracedReference<v8::Object>& wrapper) {
   return GetInternalField<WrapperTypeInfo, kV8DOMWrapperTypeIndex>(wrapper);
 }
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc b/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc
index 919704c..66a92ce 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc
@@ -98,21 +98,21 @@
     return 0;
 
   const String& text = GetText();
+  const StringView word(text, word_start, word_len);
+  const unsigned word_offset = offset - word_start;
   if (backwards) {
-    unsigned before_index = offset - word_start;
-    if (before_index <= Hyphenation::kMinimumPrefixLength)
+    if (word_offset < Hyphenation::kMinimumPrefixLength)
       return 0;
-    unsigned prefix_length = hyphenation_->LastHyphenLocation(
-        StringView(text, word_start, word_len), before_index);
-    DCHECK(!prefix_length || prefix_length < before_index);
+    unsigned prefix_length =
+        hyphenation_->LastHyphenLocation(word, word_offset + 1);
+    DCHECK(!prefix_length || prefix_length <= word_offset);
     return prefix_length;
   } else {
-    unsigned after_index = offset - word_start;
-    if (word_len <= after_index + Hyphenation::kMinimumSuffixLength)
+    if (word_len - word_offset < Hyphenation::kMinimumSuffixLength)
       return 0;
     unsigned prefix_length = hyphenation_->FirstHyphenLocation(
-        StringView(text, word_start, word_len), after_index);
-    DCHECK(!prefix_length || prefix_length > after_index);
+        word, word_offset ? word_offset - 1 : 0);
+    DCHECK(!prefix_length || prefix_length >= word_offset);
     return prefix_length;
   }
 }
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/compositor_priority_experiments.cc b/third_party/blink/renderer/platform/scheduler/main_thread/compositor_priority_experiments.cc
index 8c5b26f..1d71e34 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/compositor_priority_experiments.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/compositor_priority_experiments.cc
@@ -213,8 +213,8 @@
                     MainThreadTaskQueue::TaskTiming* task_timing,
                     bool have_seen_stop_signal) {
   if (have_seen_stop_signal) {
-    compositor_budget_pool_->RecordTaskRunTime(queue, task_timing->start_time(),
-                                               task_timing->end_time());
+    compositor_budget_pool_->RecordTaskRunTime(
+        nullptr, task_timing->start_time(), task_timing->end_time());
   }
   UpdateCompositorBudgetState(task_timing->end_time());
 }
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/find_in_page_budget_pool_controller.cc b/third_party/blink/renderer/platform/scheduler/main_thread/find_in_page_budget_pool_controller.cc
index 7b8fd2d..b6311a09 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/find_in_page_budget_pool_controller.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/find_in_page_budget_pool_controller.cc
@@ -59,7 +59,7 @@
   if (queue->GetPrioritisationType() ==
       MainThreadTaskQueue::QueueTraits::PrioritisationType::kFindInPage) {
     find_in_page_budget_pool_->RecordTaskRunTime(
-        queue, task_timing->start_time(), task_timing->end_time());
+        nullptr, task_timing->start_time(), task_timing->end_time());
   }
 
   bool is_exhausted = !find_in_page_budget_pool_->CanRunTasksAt(
diff --git a/third_party/blink/tools/blinkpy/common/system/executive.py b/third_party/blink/tools/blinkpy/common/system/executive.py
index 316c6cc1..5b48480 100644
--- a/third_party/blink/tools/blinkpy/common/system/executive.py
+++ b/third_party/blink/tools/blinkpy/common/system/executive.py
@@ -149,6 +149,13 @@
             if error.errno == errno.ECHILD:
                 # Can't wait on a non-child process, but the kill worked.
                 return
+            if error.errno == errno.EPERM and \
+                    kill_tree and sys.platform == 'darwin':
+                # Calling killpg on a process group whose leader is defunct
+                # causes a permission error on macOS, in which case we try to
+                # collect the defunct process.
+                if os.waitpid(pid, os.WNOHANG) == (0, 0):
+                    return
             raise
 
     def _win32_check_running_pid(self, pid):
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index ab41c5c5..a997930 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1637,16 +1637,12 @@
 crbug.com/1022182 virtual/module-top-level-await/external/wpt/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise.html [ Pass ]
 
 crbug.com/676270 external/wpt/css/css-text/hyphens/hyphens-auto-001.html [ Failure ]
-crbug.com/1022415 external/wpt/css/css-text/hyphens/hyphens-auto-010.html [ Failure ]
-crbug.com/1022415 [ Linux ] external/wpt/css/css-text/hyphens/hyphens-auto-inline-010.html [ Failure ]
-crbug.com/1022415 [ Win ] external/wpt/css/css-text/hyphens/hyphens-auto-inline-010.html [ Failure ]
 crbug.com/963369 external/wpt/css/css-text/hyphens/hyphens-out-of-flow-001.html [ Failure ]
 crbug.com/963369 external/wpt/css/css-text/hyphens/hyphens-out-of-flow-002.html [ Failure ]
 crbug.com/639223 external/wpt/css/css-text/hyphens/hyphens-shaping-002.html [ Failure ]
 crbug.com/639223 external/wpt/css/css-text/hyphens/hyphens-span-001.html [ Failure ]
 crbug.com/639223 external/wpt/css/css-text/hyphens/hyphens-span-002.html [ Failure ]
 crbug.com/639223 external/wpt/css/css-text/hyphens/shy-styling-001.html [ Failure ]
-crbug.com/870219 virtual/text-antialias/hyphens/hyphen-min-preferred-width-mock.html [ Failure ]
 crbug.com/870219 virtual/text-antialias/hyphens/hyphens-auto-mock.html [ Failure ]
 crbug.com/1139693 virtual/text-antialias/hyphens/midword-break-priority.html [ Failure ]
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-001-ref.html
new file mode 100644
index 0000000..7efcc11
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-001-ref.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Verifies overflow-clip-margin extends outside bounds</title>
+<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#propdef-overflow-clip-margin">
+<link rel="author" title="Scott Violet" href="mailto:sky@chromium.org">
+<style>
+  .container {
+      display: flex;
+  }
+  .parent {
+      position: relative;
+      top: -10px;
+      left: -10px;
+      width: 120px;
+      height: 120px;
+      flex: none;
+      background-color: green;
+  }
+  .spacer {
+      flex: none;
+      height: 100px;
+      width: 100px;
+  }
+
+</style>
+<p>You should see two green squares touching each other. The one on the
+  right should be slightly larger.</p>
+<div class="spacer"></div>
+<div class="container">
+  <div class="spacer" style="background-color: green"></div>
+  <div class="parent"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-001.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-001.html
new file mode 100644
index 0000000..9a97f94
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-001.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Verifies overflow-clip-margin extends outside bounds</title>
+<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#propdef-overflow-clip-margin">
+<link rel="author" title="Scott Violet" href="mailto:sky@chromium.org">
+<link rel="match" href="overflow-clip-margin-001-ref.html">
+<style>
+  .container {
+      display: flex;
+  }
+  .parent {
+      width: 100px;
+      height: 100px;
+      flex: none;
+      overflow: clip;
+      overflow-clip-margin: 10px;
+  }
+  .child {
+      width: 200px;
+      height: 200px;
+      position: relative;
+      top: -50px;
+      left: -50px;
+      background-color: green;
+  }
+  .spacer {
+      flex: none;
+      height: 100px;
+      width: 100px;
+  }
+
+</style>
+<p>You should see two green squares touching each other. The one on the
+  right should be slightly larger.</p>
+<div class="spacer"></div>
+<div class="container">
+  <div class="spacer" style="width: 90px; background-color: green"></div>
+  <div class="spacer" style="width: 10px"></div>
+  <div class="parent">
+    <div class="child"></div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-002-ref.html
new file mode 100644
index 0000000..84110e57
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-002-ref.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Verifies overflow-clip-margin impacts layout</title>
+<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#propdef-overflow-clip-margin">
+<link rel="author" title="Scott Violet" href="mailto:sky@chromium.org">
+<style>
+  .scroller {
+      overflow: auto;
+      width: 100px;
+      height: 100px;
+  }
+  .child {
+      position: relative;
+      width: 110px;
+      height: 110px;
+      background-color: green;
+  }
+</style>
+<p>You should see a green box with scrollbars.</p>
+<div class="scroller">
+  <div class="child"></div>
+</div>
+
+<p>You should see a green box with scrollbars.</p>
+<div class="scroller">
+  <div class="child" style="width: 150px; height: 150px"></div>
+</div>
+
+<p>You should see a green box with no scrollbars.</p>
+<div class="scroller" style="background-color: green">
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-002.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-002.html
new file mode 100644
index 0000000..79dcaad6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-002.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Verifies overflow-clip-margin impacts layout</title>
+<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#propdef-overflow-clip-margin">
+<link rel="author" title="Scott Violet" href="mailto:sky@chromium.org">
+<link rel="match" href="overflow-clip-margin-002-ref.html">
+<style>
+  .scroller {
+      overflow: auto;
+      width: 100px;
+      height: 100px;
+  }
+  .parent {
+      width: 100px;
+      height: 100px;
+      overflow: clip;
+      overflow-clip-margin: 10px;
+  }
+  .child {
+      width: 200px;
+      height: 200px;
+      position: relative;
+      top: -50px;
+      left: -50px;
+      background-color: green;
+  }
+</style>
+<p>You should see a green box with scrollbars.</p>
+<div class="scroller">
+  <div class="parent">
+    <div class="child"></div>
+  </div>
+</div>
+
+<p>You should see a green box with scrollbars.</p>
+<div class="scroller">
+  <div class="parent" style="overflow-clip-margin: 100px">
+    <div class="child"></div>
+  </div>
+</div>
+
+<p>You should see a green box with no scrollbars.</p>
+<div class="scroller">
+  <div class="parent" style="background-color: green">
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-003-ref.html
new file mode 100644
index 0000000..cf6b55a2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-003-ref.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Verifies overflow-clip-margin doesn't impact paint effects</title>
+<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#propdef-overflow-clip-margin">
+<link rel="author" title="Scott Violet" href="mailto:sky@chromium.org">
+<style>
+  .parent {
+      width: 100px;
+      height: 100px;
+      background-color: green;
+      box-shadow: 20px 20px 5px red;
+  }
+</style>
+<p>You should see a green box with a red box shadow.
+<div class="parent"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-003.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-003.html
new file mode 100644
index 0000000..52625e9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-003.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Verifies overflow-clip-margin doesn't impact paint effects</title>
+<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#propdef-overflow-clip-margin">
+<link rel="author" title="Scott Violet" href="mailto:sky@chromium.org">
+<link rel="match" href="overflow-clip-margin-003-ref.html">
+<style>
+  .parent {
+      width: 100px;
+      height: 100px;
+      background-color: green;
+      overflow: clip;
+      overflow-clip-margin: 1px;
+      box-shadow: 20px 20px 5px red;
+  }
+</style>
+<p>You should see a green box with a red box shadow.
+<div class="parent"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-invalidation-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-invalidation-ref.html
new file mode 100644
index 0000000..1ec2a5c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-invalidation-ref.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Overflow: overflow-clip-margin: invalidation on change</title>
+<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#propdef-overflow-clip-margin">
+<link rel="author" title="Scott Violet" href="mailto:sky@chromium.org">
+<style>
+  .container {
+      display: flex;
+  }
+  .parent_overflow {
+      position: relative;
+      top: -10px;
+      left: -10px;
+      width: 120px;
+      height: 120px;
+      flex: none;
+      background-color: green;
+  }
+  .parent {
+      width: 100px;
+      height: 100px;
+      flex: none;
+      background-color: green;
+  }
+  .spacer {
+      flex: none;
+      height: 100px;
+      width: 100px;
+  }
+
+</style>
+<div class="spacer"></div>
+<div class="container">
+  <div class="spacer"></div>
+  <div class="parent"></div>
+<div class="spacer"></div>
+<div class="container">
+  <div class="spacer"></div>
+  <div class="parent_overflow"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-invalidation.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-invalidation.html
new file mode 100644
index 0000000..d9c87a3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-invalidation.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<title>CSS Overflow: overflow-clip-margin: invalidation on change</title>
+<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#propdef-overflow-clip-margin">
+<meta name="assert" content="overflow-clip-margin: toggling should invalidate.">
+<link rel="author" title="Scott Violet" href="mailto:sky@chromium.org">
+<link rel="match" href="overflow-clip-margin-invalidation-ref.html">
+<style>
+  .container {
+      display: flex;
+  }
+  .parent {
+      flex: none;
+      width: 100px;
+      height: 100px;
+      flex: none;
+      overflow: clip;
+  }
+  .child {
+      width: 200px;
+      height: 200px;
+      position: relative;
+      top: -50px;
+      left: -50px;
+      background-color: green;
+  }
+  .spacer {
+      flex: none;
+      height: 100px;
+      width: 100px;
+  }
+  .margin {
+    overflow-clip-margin: 10px;
+  }
+</style>
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+</head>
+<body>
+<div class="spacer"></div>
+<div class="container">
+  <div class="spacer"></div>
+  <div id="div_with_margin" class="parent margin">
+    <div class="child"></div>
+  </div>
+<div class="spacer"></div>
+<div class="container">
+  <div class="spacer"></div>
+  <div id="div_without_margin" class="parent">
+    <div class="child"></div>
+  </div>
+</body>
+<script>
+async function runTest() {
+  document.getElementById('div_with_margin').classList.remove("margin");
+  document.getElementById('div_without_margin').classList.add("margin");
+  takeScreenshot();
+}
+onload = () => {
+  waitForAtLeastOneFrame().then(() => { runTest() });
+}
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-auto-010.html b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-auto-010.html
index 01acaf0..1aac0bf2 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-auto-010.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-auto-010.html
@@ -35,4 +35,4 @@
 
  <body lang="en">
 
-  <div>regulation implementation</div>
+  <div>regulation implementation now</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-auto-inline-010.html b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-auto-inline-010.html
index 03776617..ebeef66 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-auto-inline-010.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-auto-inline-010.html
@@ -39,14 +39,14 @@
 
  <body lang="en">
 
-  <div>There are <span>new guidelines now</span>.</div>
+  <div>There are <span>new engines now</span>.</div>
 
   <!--
         Expected result:
         There
         are
         new
-        guide-
-        lines
+        en-
+        gines
         now.
   -->
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-none-012.html b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-none-012.html
index 5b70c95..47e72a4 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-none-012.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-none-012.html
@@ -22,7 +22,7 @@
     }
   </style>
 
-  <div>regu&#x002D;lation imple&#x002D;menta&#x002D;tion</div>
+  <div>regu&#x002D;lation imple&#x002D;menta&#x002D;tion now</div>
 
   <!--
         Expected result:
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-none-013.html b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-none-013.html
index d234cc0..30f207ba 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-none-013.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/hyphens-none-013.html
@@ -22,7 +22,7 @@
     }
   </style>
 
-  <div>regu&#x2010;lation imple&#x2010;menta&#x2010;tion</div>
+  <div>regu&#x2010;lation imple&#x2010;menta&#x2010;tion now</div>
 
   <!--
         Expected result:
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-010H-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-010H-ref.html
index 861f0ed..6d453b9 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-010H-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-010H-ref.html
@@ -18,7 +18,7 @@
 
  <body lang="en">
 
-  <div>regu&#x2010;<br>lation<br>imple&#x2010;<br>menta&#x2010;<br>tion</div>
+  <div>regu&#x2010;<br>lation<br>imple&#x2010;<br>menta&#x2010;<br>tion<br>now</div>
 
 <!--
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-010M-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-010M-ref.html
index d6c0065..27adc3f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-010M-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-010M-ref.html
@@ -18,7 +18,7 @@
 
  <body lang="en">
 
-  <div>regu&#x002D;<br>lation<br>imple&#x002D;<br>menta&#x002D;<br>tion</div>
+  <div>regu&#x002D;<br>lation<br>imple&#x002D;<br>menta&#x002D;<br>tion<br>now</div>
 
 <!--
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-inline-010H-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-inline-010H-ref.html
index c3e6271..0a3aedf 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-inline-010H-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-inline-010H-ref.html
@@ -18,7 +18,7 @@
 
  <body lang="en">
 
-  <div>There<br>are<br>new<br>guide&#x2010;<br>lines<br>now.</div>
+  <div>There<br>are<br>new<br>en&#x2010;<br>gines<br>now.</div>
 
 <!--
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-inline-010M-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-inline-010M-ref.html
index ace0c5e..59f5247 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-inline-010M-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/hyphens/reference/hyphens-auto-inline-010M-ref.html
@@ -18,7 +18,7 @@
 
  <body lang="en">
 
-  <div>There<br>are<br>new<br>guide&#x002D;<br>lines<br>now.</div>
+  <div>There<br>are<br>new<br>en&#x002D;<br>gines<br>now.</div>
 
 <!--
 
diff --git a/third_party/blink/web_tests/external/wpt/streams/idlharness.any-expected.txt b/third_party/blink/web_tests/external/wpt/streams/idlharness.any-expected.txt
index f9cb7f3b..2af3b75 100644
--- a/third_party/blink/web_tests/external/wpt/streams/idlharness.any-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/idlharness.any-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 224 tests; 116 PASS, 108 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 224 tests; 126 PASS, 98 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS idl_test validation
 PASS ReadableStreamDefaultReader includes ReadableStreamGenericReader: member names are unique
@@ -10,12 +10,12 @@
 PASS ReadableStream interface: existence and properties of interface prototype object
 PASS ReadableStream interface: existence and properties of interface prototype object's "constructor" property
 PASS ReadableStream interface: existence and properties of interface prototype object's @@unscopables property
-FAIL ReadableStream interface: attribute locked assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation cancel(optional any) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation getReader(optional ReadableStreamGetReaderOptions) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation pipeThrough(ReadableWritablePair, optional StreamPipeOptions) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation pipeTo(WritableStream, optional StreamPipeOptions) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation tee() assert_true: property should be enumerable expected true got false
+PASS ReadableStream interface: attribute locked
+PASS ReadableStream interface: operation cancel(optional any)
+PASS ReadableStream interface: operation getReader(optional ReadableStreamGetReaderOptions)
+PASS ReadableStream interface: operation pipeThrough(ReadableWritablePair, optional StreamPipeOptions)
+PASS ReadableStream interface: operation pipeTo(WritableStream, optional StreamPipeOptions)
+PASS ReadableStream interface: operation tee()
 FAIL ReadableStream interface: async iterable<any> Cannot read property 'writable' of undefined
 PASS ReadableStream must be primary interface of new ReadableStream()
 PASS Stringification of new ReadableStream()
@@ -35,10 +35,10 @@
 PASS ReadableStreamDefaultReader interface: existence and properties of interface prototype object
 PASS ReadableStreamDefaultReader interface: existence and properties of interface prototype object's "constructor" property
 PASS ReadableStreamDefaultReader interface: existence and properties of interface prototype object's @@unscopables property
-FAIL ReadableStreamDefaultReader interface: operation read() assert_true: property should be enumerable expected true got false
-FAIL ReadableStreamDefaultReader interface: operation releaseLock() assert_true: property should be enumerable expected true got false
-FAIL ReadableStreamDefaultReader interface: attribute closed assert_true: property should be enumerable expected true got false
-FAIL ReadableStreamDefaultReader interface: operation cancel(optional any) assert_true: property should be enumerable expected true got false
+PASS ReadableStreamDefaultReader interface: operation read()
+PASS ReadableStreamDefaultReader interface: operation releaseLock()
+PASS ReadableStreamDefaultReader interface: attribute closed
+PASS ReadableStreamDefaultReader interface: operation cancel(optional any)
 PASS ReadableStreamDefaultReader must be primary interface of (new ReadableStream()).getReader()
 PASS Stringification of (new ReadableStream()).getReader()
 PASS ReadableStreamDefaultReader interface: (new ReadableStream()).getReader() must inherit property "read()" with the proper type
@@ -124,10 +124,10 @@
 PASS WritableStream interface: existence and properties of interface prototype object
 PASS WritableStream interface: existence and properties of interface prototype object's "constructor" property
 PASS WritableStream interface: existence and properties of interface prototype object's @@unscopables property
-FAIL WritableStream interface: attribute locked assert_true: property should be enumerable expected true got false
-FAIL WritableStream interface: operation abort(optional any) assert_true: property should be enumerable expected true got false
-FAIL WritableStream interface: operation close() assert_true: property should be enumerable expected true got false
-FAIL WritableStream interface: operation getWriter() assert_true: property should be enumerable expected true got false
+PASS WritableStream interface: attribute locked
+PASS WritableStream interface: operation abort(optional any)
+PASS WritableStream interface: operation close()
+PASS WritableStream interface: operation getWriter()
 PASS WritableStream must be primary interface of new WritableStream()
 PASS Stringification of new WritableStream()
 PASS WritableStream interface: new WritableStream() must inherit property "locked" with the proper type
@@ -141,13 +141,13 @@
 PASS WritableStreamDefaultWriter interface: existence and properties of interface prototype object
 PASS WritableStreamDefaultWriter interface: existence and properties of interface prototype object's "constructor" property
 PASS WritableStreamDefaultWriter interface: existence and properties of interface prototype object's @@unscopables property
-FAIL WritableStreamDefaultWriter interface: attribute closed assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: attribute desiredSize assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: attribute ready assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: operation abort(optional any) assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: operation close() assert_true: property should be enumerable expected true got false
+PASS WritableStreamDefaultWriter interface: attribute closed
+PASS WritableStreamDefaultWriter interface: attribute desiredSize
+PASS WritableStreamDefaultWriter interface: attribute ready
+PASS WritableStreamDefaultWriter interface: operation abort(optional any)
+PASS WritableStreamDefaultWriter interface: operation close()
 FAIL WritableStreamDefaultWriter interface: operation releaseLock() assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: operation write(optional any) assert_true: property should be enumerable expected true got false
+PASS WritableStreamDefaultWriter interface: operation write(optional any)
 PASS WritableStreamDefaultWriter must be primary interface of (new WritableStream()).getWriter()
 PASS Stringification of (new WritableStream()).getWriter()
 PASS WritableStreamDefaultWriter interface: (new WritableStream()).getWriter() must inherit property "closed" with the proper type
diff --git a/third_party/blink/web_tests/external/wpt/streams/idlharness.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/idlharness.any.serviceworker-expected.txt
index f9cb7f3b..2af3b75 100644
--- a/third_party/blink/web_tests/external/wpt/streams/idlharness.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/idlharness.any.serviceworker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 224 tests; 116 PASS, 108 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 224 tests; 126 PASS, 98 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS idl_test validation
 PASS ReadableStreamDefaultReader includes ReadableStreamGenericReader: member names are unique
@@ -10,12 +10,12 @@
 PASS ReadableStream interface: existence and properties of interface prototype object
 PASS ReadableStream interface: existence and properties of interface prototype object's "constructor" property
 PASS ReadableStream interface: existence and properties of interface prototype object's @@unscopables property
-FAIL ReadableStream interface: attribute locked assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation cancel(optional any) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation getReader(optional ReadableStreamGetReaderOptions) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation pipeThrough(ReadableWritablePair, optional StreamPipeOptions) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation pipeTo(WritableStream, optional StreamPipeOptions) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation tee() assert_true: property should be enumerable expected true got false
+PASS ReadableStream interface: attribute locked
+PASS ReadableStream interface: operation cancel(optional any)
+PASS ReadableStream interface: operation getReader(optional ReadableStreamGetReaderOptions)
+PASS ReadableStream interface: operation pipeThrough(ReadableWritablePair, optional StreamPipeOptions)
+PASS ReadableStream interface: operation pipeTo(WritableStream, optional StreamPipeOptions)
+PASS ReadableStream interface: operation tee()
 FAIL ReadableStream interface: async iterable<any> Cannot read property 'writable' of undefined
 PASS ReadableStream must be primary interface of new ReadableStream()
 PASS Stringification of new ReadableStream()
@@ -35,10 +35,10 @@
 PASS ReadableStreamDefaultReader interface: existence and properties of interface prototype object
 PASS ReadableStreamDefaultReader interface: existence and properties of interface prototype object's "constructor" property
 PASS ReadableStreamDefaultReader interface: existence and properties of interface prototype object's @@unscopables property
-FAIL ReadableStreamDefaultReader interface: operation read() assert_true: property should be enumerable expected true got false
-FAIL ReadableStreamDefaultReader interface: operation releaseLock() assert_true: property should be enumerable expected true got false
-FAIL ReadableStreamDefaultReader interface: attribute closed assert_true: property should be enumerable expected true got false
-FAIL ReadableStreamDefaultReader interface: operation cancel(optional any) assert_true: property should be enumerable expected true got false
+PASS ReadableStreamDefaultReader interface: operation read()
+PASS ReadableStreamDefaultReader interface: operation releaseLock()
+PASS ReadableStreamDefaultReader interface: attribute closed
+PASS ReadableStreamDefaultReader interface: operation cancel(optional any)
 PASS ReadableStreamDefaultReader must be primary interface of (new ReadableStream()).getReader()
 PASS Stringification of (new ReadableStream()).getReader()
 PASS ReadableStreamDefaultReader interface: (new ReadableStream()).getReader() must inherit property "read()" with the proper type
@@ -124,10 +124,10 @@
 PASS WritableStream interface: existence and properties of interface prototype object
 PASS WritableStream interface: existence and properties of interface prototype object's "constructor" property
 PASS WritableStream interface: existence and properties of interface prototype object's @@unscopables property
-FAIL WritableStream interface: attribute locked assert_true: property should be enumerable expected true got false
-FAIL WritableStream interface: operation abort(optional any) assert_true: property should be enumerable expected true got false
-FAIL WritableStream interface: operation close() assert_true: property should be enumerable expected true got false
-FAIL WritableStream interface: operation getWriter() assert_true: property should be enumerable expected true got false
+PASS WritableStream interface: attribute locked
+PASS WritableStream interface: operation abort(optional any)
+PASS WritableStream interface: operation close()
+PASS WritableStream interface: operation getWriter()
 PASS WritableStream must be primary interface of new WritableStream()
 PASS Stringification of new WritableStream()
 PASS WritableStream interface: new WritableStream() must inherit property "locked" with the proper type
@@ -141,13 +141,13 @@
 PASS WritableStreamDefaultWriter interface: existence and properties of interface prototype object
 PASS WritableStreamDefaultWriter interface: existence and properties of interface prototype object's "constructor" property
 PASS WritableStreamDefaultWriter interface: existence and properties of interface prototype object's @@unscopables property
-FAIL WritableStreamDefaultWriter interface: attribute closed assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: attribute desiredSize assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: attribute ready assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: operation abort(optional any) assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: operation close() assert_true: property should be enumerable expected true got false
+PASS WritableStreamDefaultWriter interface: attribute closed
+PASS WritableStreamDefaultWriter interface: attribute desiredSize
+PASS WritableStreamDefaultWriter interface: attribute ready
+PASS WritableStreamDefaultWriter interface: operation abort(optional any)
+PASS WritableStreamDefaultWriter interface: operation close()
 FAIL WritableStreamDefaultWriter interface: operation releaseLock() assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: operation write(optional any) assert_true: property should be enumerable expected true got false
+PASS WritableStreamDefaultWriter interface: operation write(optional any)
 PASS WritableStreamDefaultWriter must be primary interface of (new WritableStream()).getWriter()
 PASS Stringification of (new WritableStream()).getWriter()
 PASS WritableStreamDefaultWriter interface: (new WritableStream()).getWriter() must inherit property "closed" with the proper type
diff --git a/third_party/blink/web_tests/external/wpt/streams/idlharness.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/idlharness.any.sharedworker-expected.txt
index f9cb7f3b..2af3b75 100644
--- a/third_party/blink/web_tests/external/wpt/streams/idlharness.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/idlharness.any.sharedworker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 224 tests; 116 PASS, 108 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 224 tests; 126 PASS, 98 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS idl_test validation
 PASS ReadableStreamDefaultReader includes ReadableStreamGenericReader: member names are unique
@@ -10,12 +10,12 @@
 PASS ReadableStream interface: existence and properties of interface prototype object
 PASS ReadableStream interface: existence and properties of interface prototype object's "constructor" property
 PASS ReadableStream interface: existence and properties of interface prototype object's @@unscopables property
-FAIL ReadableStream interface: attribute locked assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation cancel(optional any) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation getReader(optional ReadableStreamGetReaderOptions) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation pipeThrough(ReadableWritablePair, optional StreamPipeOptions) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation pipeTo(WritableStream, optional StreamPipeOptions) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation tee() assert_true: property should be enumerable expected true got false
+PASS ReadableStream interface: attribute locked
+PASS ReadableStream interface: operation cancel(optional any)
+PASS ReadableStream interface: operation getReader(optional ReadableStreamGetReaderOptions)
+PASS ReadableStream interface: operation pipeThrough(ReadableWritablePair, optional StreamPipeOptions)
+PASS ReadableStream interface: operation pipeTo(WritableStream, optional StreamPipeOptions)
+PASS ReadableStream interface: operation tee()
 FAIL ReadableStream interface: async iterable<any> Cannot read property 'writable' of undefined
 PASS ReadableStream must be primary interface of new ReadableStream()
 PASS Stringification of new ReadableStream()
@@ -35,10 +35,10 @@
 PASS ReadableStreamDefaultReader interface: existence and properties of interface prototype object
 PASS ReadableStreamDefaultReader interface: existence and properties of interface prototype object's "constructor" property
 PASS ReadableStreamDefaultReader interface: existence and properties of interface prototype object's @@unscopables property
-FAIL ReadableStreamDefaultReader interface: operation read() assert_true: property should be enumerable expected true got false
-FAIL ReadableStreamDefaultReader interface: operation releaseLock() assert_true: property should be enumerable expected true got false
-FAIL ReadableStreamDefaultReader interface: attribute closed assert_true: property should be enumerable expected true got false
-FAIL ReadableStreamDefaultReader interface: operation cancel(optional any) assert_true: property should be enumerable expected true got false
+PASS ReadableStreamDefaultReader interface: operation read()
+PASS ReadableStreamDefaultReader interface: operation releaseLock()
+PASS ReadableStreamDefaultReader interface: attribute closed
+PASS ReadableStreamDefaultReader interface: operation cancel(optional any)
 PASS ReadableStreamDefaultReader must be primary interface of (new ReadableStream()).getReader()
 PASS Stringification of (new ReadableStream()).getReader()
 PASS ReadableStreamDefaultReader interface: (new ReadableStream()).getReader() must inherit property "read()" with the proper type
@@ -124,10 +124,10 @@
 PASS WritableStream interface: existence and properties of interface prototype object
 PASS WritableStream interface: existence and properties of interface prototype object's "constructor" property
 PASS WritableStream interface: existence and properties of interface prototype object's @@unscopables property
-FAIL WritableStream interface: attribute locked assert_true: property should be enumerable expected true got false
-FAIL WritableStream interface: operation abort(optional any) assert_true: property should be enumerable expected true got false
-FAIL WritableStream interface: operation close() assert_true: property should be enumerable expected true got false
-FAIL WritableStream interface: operation getWriter() assert_true: property should be enumerable expected true got false
+PASS WritableStream interface: attribute locked
+PASS WritableStream interface: operation abort(optional any)
+PASS WritableStream interface: operation close()
+PASS WritableStream interface: operation getWriter()
 PASS WritableStream must be primary interface of new WritableStream()
 PASS Stringification of new WritableStream()
 PASS WritableStream interface: new WritableStream() must inherit property "locked" with the proper type
@@ -141,13 +141,13 @@
 PASS WritableStreamDefaultWriter interface: existence and properties of interface prototype object
 PASS WritableStreamDefaultWriter interface: existence and properties of interface prototype object's "constructor" property
 PASS WritableStreamDefaultWriter interface: existence and properties of interface prototype object's @@unscopables property
-FAIL WritableStreamDefaultWriter interface: attribute closed assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: attribute desiredSize assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: attribute ready assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: operation abort(optional any) assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: operation close() assert_true: property should be enumerable expected true got false
+PASS WritableStreamDefaultWriter interface: attribute closed
+PASS WritableStreamDefaultWriter interface: attribute desiredSize
+PASS WritableStreamDefaultWriter interface: attribute ready
+PASS WritableStreamDefaultWriter interface: operation abort(optional any)
+PASS WritableStreamDefaultWriter interface: operation close()
 FAIL WritableStreamDefaultWriter interface: operation releaseLock() assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: operation write(optional any) assert_true: property should be enumerable expected true got false
+PASS WritableStreamDefaultWriter interface: operation write(optional any)
 PASS WritableStreamDefaultWriter must be primary interface of (new WritableStream()).getWriter()
 PASS Stringification of (new WritableStream()).getWriter()
 PASS WritableStreamDefaultWriter interface: (new WritableStream()).getWriter() must inherit property "closed" with the proper type
diff --git a/third_party/blink/web_tests/external/wpt/streams/idlharness.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/idlharness.any.worker-expected.txt
index f9cb7f3b..2af3b75 100644
--- a/third_party/blink/web_tests/external/wpt/streams/idlharness.any.worker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/idlharness.any.worker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 224 tests; 116 PASS, 108 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 224 tests; 126 PASS, 98 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS idl_test validation
 PASS ReadableStreamDefaultReader includes ReadableStreamGenericReader: member names are unique
@@ -10,12 +10,12 @@
 PASS ReadableStream interface: existence and properties of interface prototype object
 PASS ReadableStream interface: existence and properties of interface prototype object's "constructor" property
 PASS ReadableStream interface: existence and properties of interface prototype object's @@unscopables property
-FAIL ReadableStream interface: attribute locked assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation cancel(optional any) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation getReader(optional ReadableStreamGetReaderOptions) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation pipeThrough(ReadableWritablePair, optional StreamPipeOptions) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation pipeTo(WritableStream, optional StreamPipeOptions) assert_true: property should be enumerable expected true got false
-FAIL ReadableStream interface: operation tee() assert_true: property should be enumerable expected true got false
+PASS ReadableStream interface: attribute locked
+PASS ReadableStream interface: operation cancel(optional any)
+PASS ReadableStream interface: operation getReader(optional ReadableStreamGetReaderOptions)
+PASS ReadableStream interface: operation pipeThrough(ReadableWritablePair, optional StreamPipeOptions)
+PASS ReadableStream interface: operation pipeTo(WritableStream, optional StreamPipeOptions)
+PASS ReadableStream interface: operation tee()
 FAIL ReadableStream interface: async iterable<any> Cannot read property 'writable' of undefined
 PASS ReadableStream must be primary interface of new ReadableStream()
 PASS Stringification of new ReadableStream()
@@ -35,10 +35,10 @@
 PASS ReadableStreamDefaultReader interface: existence and properties of interface prototype object
 PASS ReadableStreamDefaultReader interface: existence and properties of interface prototype object's "constructor" property
 PASS ReadableStreamDefaultReader interface: existence and properties of interface prototype object's @@unscopables property
-FAIL ReadableStreamDefaultReader interface: operation read() assert_true: property should be enumerable expected true got false
-FAIL ReadableStreamDefaultReader interface: operation releaseLock() assert_true: property should be enumerable expected true got false
-FAIL ReadableStreamDefaultReader interface: attribute closed assert_true: property should be enumerable expected true got false
-FAIL ReadableStreamDefaultReader interface: operation cancel(optional any) assert_true: property should be enumerable expected true got false
+PASS ReadableStreamDefaultReader interface: operation read()
+PASS ReadableStreamDefaultReader interface: operation releaseLock()
+PASS ReadableStreamDefaultReader interface: attribute closed
+PASS ReadableStreamDefaultReader interface: operation cancel(optional any)
 PASS ReadableStreamDefaultReader must be primary interface of (new ReadableStream()).getReader()
 PASS Stringification of (new ReadableStream()).getReader()
 PASS ReadableStreamDefaultReader interface: (new ReadableStream()).getReader() must inherit property "read()" with the proper type
@@ -124,10 +124,10 @@
 PASS WritableStream interface: existence and properties of interface prototype object
 PASS WritableStream interface: existence and properties of interface prototype object's "constructor" property
 PASS WritableStream interface: existence and properties of interface prototype object's @@unscopables property
-FAIL WritableStream interface: attribute locked assert_true: property should be enumerable expected true got false
-FAIL WritableStream interface: operation abort(optional any) assert_true: property should be enumerable expected true got false
-FAIL WritableStream interface: operation close() assert_true: property should be enumerable expected true got false
-FAIL WritableStream interface: operation getWriter() assert_true: property should be enumerable expected true got false
+PASS WritableStream interface: attribute locked
+PASS WritableStream interface: operation abort(optional any)
+PASS WritableStream interface: operation close()
+PASS WritableStream interface: operation getWriter()
 PASS WritableStream must be primary interface of new WritableStream()
 PASS Stringification of new WritableStream()
 PASS WritableStream interface: new WritableStream() must inherit property "locked" with the proper type
@@ -141,13 +141,13 @@
 PASS WritableStreamDefaultWriter interface: existence and properties of interface prototype object
 PASS WritableStreamDefaultWriter interface: existence and properties of interface prototype object's "constructor" property
 PASS WritableStreamDefaultWriter interface: existence and properties of interface prototype object's @@unscopables property
-FAIL WritableStreamDefaultWriter interface: attribute closed assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: attribute desiredSize assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: attribute ready assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: operation abort(optional any) assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: operation close() assert_true: property should be enumerable expected true got false
+PASS WritableStreamDefaultWriter interface: attribute closed
+PASS WritableStreamDefaultWriter interface: attribute desiredSize
+PASS WritableStreamDefaultWriter interface: attribute ready
+PASS WritableStreamDefaultWriter interface: operation abort(optional any)
+PASS WritableStreamDefaultWriter interface: operation close()
 FAIL WritableStreamDefaultWriter interface: operation releaseLock() assert_true: property should be enumerable expected true got false
-FAIL WritableStreamDefaultWriter interface: operation write(optional any) assert_true: property should be enumerable expected true got false
+PASS WritableStreamDefaultWriter interface: operation write(optional any)
 PASS WritableStreamDefaultWriter must be primary interface of (new WritableStream()).getWriter()
 PASS Stringification of (new WritableStream()).getWriter()
 PASS WritableStreamDefaultWriter interface: (new WritableStream()).getWriter() must inherit property "closed" with the proper type
diff --git a/third_party/blink/web_tests/virtual/text-antialias/hyphens/hyphen-min-preferred-width-mock-expected.html b/third_party/blink/web_tests/virtual/text-antialias/hyphens/hyphen-min-preferred-width-mock-expected.html
index 5442dc0..5fa6dfda 100644
--- a/third_party/blink/web_tests/virtual/text-antialias/hyphens/hyphen-min-preferred-width-mock-expected.html
+++ b/third_party/blink/web_tests/virtual/text-antialias/hyphens/hyphen-min-preferred-width-mock-expected.html
@@ -1,8 +1,9 @@
 <!DOCTYPE html>
+<script src="../../../resources/ahem.js"></script>
 <style>
 div {
   display: inline-block;
-  font: 20px Times;
+  font: 20px Ahem;
 }
 </style>
 <div lang="en-us">
diff --git a/third_party/blink/web_tests/virtual/text-antialias/hyphens/hyphen-min-preferred-width-mock.html b/third_party/blink/web_tests/virtual/text-antialias/hyphens/hyphen-min-preferred-width-mock.html
index 195544c..b7cca7a 100644
--- a/third_party/blink/web_tests/virtual/text-antialias/hyphens/hyphen-min-preferred-width-mock.html
+++ b/third_party/blink/web_tests/virtual/text-antialias/hyphens/hyphen-min-preferred-width-mock.html
@@ -1,7 +1,8 @@
 <!DOCTYPE html>
+<script src="../../../resources/ahem.js"></script>
 <style>
 div {
-  font: 20px Times;
+  font: 20px Ahem;
   -webkit-hyphens: auto;
   hyphens: auto;
 }
diff --git a/third_party/boringssl/BUILD.generated.gni b/third_party/boringssl/BUILD.generated.gni
index a136d05..c4bf5d3 100644
--- a/third_party/boringssl/BUILD.generated.gni
+++ b/third_party/boringssl/BUILD.generated.gni
@@ -198,6 +198,7 @@
   "src/crypto/trust_token/internal.h",
   "src/crypto/trust_token/pmbtoken.c",
   "src/crypto/trust_token/trust_token.c",
+  "src/crypto/trust_token/voprf.c",
   "src/crypto/x509/a_digest.c",
   "src/crypto/x509/a_sign.c",
   "src/crypto/x509/a_strex.c",
diff --git a/third_party/byte_buddy/BUILD.gn b/third_party/byte_buddy/BUILD.gn
index 66d5512..5b112565 100644
--- a/third_party/byte_buddy/BUILD.gn
+++ b/third_party/byte_buddy/BUILD.gn
@@ -8,6 +8,7 @@
   testonly = true
   supports_android = true
   enable_bytecode_checks = false
+  enable_desugar = false
   jar_path = "lib/byte-buddy.jar"
 }
 
@@ -15,6 +16,7 @@
   testonly = true
   supports_android = true
   enable_bytecode_checks = false
+  enable_desugar = false
   jar_path = "lib/byte-buddy-agent.jar"
 }
 
@@ -25,12 +27,14 @@
   supports_android = true
   requires_android = true
   no_build_hooks = true
+  enable_desugar = false
   jar_path = "android_sdk_build_tools_25_0_2/build-tools/25.0.2/lib/dx.jar"
 }
 
 android_java_prebuilt("byte_buddy_android_java") {
   testonly = true
   enable_bytecode_checks = false
+  enable_desugar = false
   deps = [ ":dx_25_0_2_java" ]
   proguard_configs = [ "//third_party/byte_buddy/proguard.flags" ]
   jar_path = "lib/byte-buddy-android.jar"
diff --git a/third_party/google-truth/BUILD.gn b/third_party/google-truth/BUILD.gn
index 5d57221..dfcc9d10 100644
--- a/third_party/google-truth/BUILD.gn
+++ b/third_party/google-truth/BUILD.gn
@@ -9,6 +9,7 @@
 
   # Uses the difflib package, which doesn't exist in third_party.
   enable_bytecode_checks = false
+  enable_desugar = false
   supports_android = true
 
   # requires_android because of dependency on guava_android.
diff --git a/third_party/webdriver/atoms.cc b/third_party/webdriver/atoms.cc
index 780e206..00a9374 100644
--- a/third_party/webdriver/atoms.cc
+++ b/third_party/webdriver/atoms.cc
@@ -3275,98 +3275,99 @@
     "f(\"normal\"==c||\"nowrap\"==c)a=a.replace(/\\n/g,\" \");a=\"pre\"==c|",
     "|\"pre-wrap\"==c?a.replace(/[ \\f\\t\\v\\u2028\\u2029]/g,\"\\u00a0\"):",
     "a.replace(/[ \\f\\t\\v\\u2028\\u2029]+/g,\" \");\"capitalize\"==d?a=a.",
-    "replace(/(^|\\s|\\b)(\\S)/g,function(e,f,g){return f+g.toUpperCase()})",
-    ":\"uppercase\"==d?a=a.toUpperCase():\"lowercase\"==d&&(a=a.toLowerCase",
-    "());c=b.pop()||\"\";wa(c)&&0==a.lastIndexOf(\" \",0)&&(a=a.substr(1));",
-    "b.push(c+a)}\nfunction nc(a){var b=1,c=W(a,\"opacity\");c&&(b=Number(c",
-    "));(a=hc(a))&&(b*=nc(a));return b}\nfunction yc(a,b,c,d,e){if(3==a.nod",
-    "eType&&c)xc(a,b,d,e);else if(T(a))if(T(a,\"CONTENT\")||T(a,\"SLOT\")){",
-    "for(var f=a;f.parentNode;)f=f.parentNode;f instanceof ShadowRoot?(a=T(",
-    "a,\"CONTENT\")?a.getDistributedNodes():a.assignedNodes(),w(a,function(",
-    "g){yc(g,b,c,d,e)})):tc(a,b)}else if(T(a,\"SHADOW\")){for(f=a;f.parentN",
-    "ode;)f=f.parentNode;if(f instanceof ShadowRoot&&(a=f))for(a=a.olderSha",
-    "dowRoot;a;)w(a.childNodes,function(g){yc(g,b,c,d,e)}),a=a.olderShadowR",
-    "oot}else tc(a,b)}\nfunction tc(a,b){a.shadowRoot&&w(a.shadowRoot.child",
-    "Nodes,function(c){yc(c,b,!0,null,null)});vc(a,b,function(c,d,e,f,g){va",
-    "r h=null;1==c.nodeType?h=c:3==c.nodeType&&(h=c);null!=h&&(null!=h.assi",
-    "gnedSlot||h.getDestinationInsertionPoints&&0<h.getDestinationInsertion",
-    "Points().length)||yc(c,d,e,f,g)})};var zc={K:function(a){return!(!a.qu",
-    "erySelectorAll||!a.querySelector)},o:function(a,b){if(!a)throw new R(3",
-    "2,\"No class name specified\");a=xa(a);if(-1!==a.indexOf(\" \"))throw ",
-    "new R(32,\"Compound class names not permitted\");if(zc.K(b))try{return",
-    " b.querySelector(\".\"+a.replace(/\\./g,\"\\\\.\"))||null}catch(c){thr",
-    "ow new R(32,\"An invalid or illegal class name was specified\");}a=C(z",
-    "(b),\"*\",a,b);return a.length?a[0]:null},i:function(a,b){if(!a)throw ",
-    "new R(32,\"No class name specified\");a=xa(a);if(-1!==a.indexOf(\" \")",
-    ")throw new R(32,\n\"Compound class names not permitted\");if(zc.K(b))t",
-    "ry{return b.querySelectorAll(\".\"+a.replace(/\\./g,\"\\\\.\"))}catch(",
-    "c){throw new R(32,\"An invalid or illegal class name was specified\");",
-    "}return C(z(b),\"*\",a,b)}};var Ac={o:function(a,b){q(b.querySelector)",
-    ";if(!a)throw new R(32,\"No selector specified\");a=xa(a);try{var c=b.q",
-    "uerySelector(a)}catch(d){throw new R(32,\"An invalid or illegal select",
-    "or was specified\");}return c&&1==c.nodeType?c:null},i:function(a,b){q",
-    "(b.querySelectorAll);if(!a)throw new R(32,\"No selector specified\");a",
-    "=xa(a);try{return b.querySelectorAll(a)}catch(c){throw new R(32,\"An i",
-    "nvalid or illegal selector was specified\");}}};var Bc={K:function(a,b",
-    "){return!(!a.querySelectorAll||!a.querySelector)&&!/^\\d.*/.test(b)},o",
-    ":function(a,b){var c=z(b),d=n(a)?c.C.getElementById(a):a;return d?cc(d",
-    ",\"id\")==a&&b!=d&&Ia(b,d)?d:sa(C(c,\"*\"),function(e){return cc(e,\"i",
-    "d\")==a&&b!=e&&Ia(b,e)}):null},i:function(a,b){if(!a)return[];if(Bc.K(",
-    "b,a))try{return b.querySelectorAll(\"#\"+Bc.ra(a))}catch(c){return[]}b",
-    "=C(z(b),\"*\",null,b);return oa(b,function(c){return cc(c,\"id\")==a})",
-    "},ra:function(a){return a.replace(/([\\s'\"\\\\#.:;,!?+<>=~*^$|%&@`{}",
-    "\\-\\/\\[\\]\\(\\)])/g,\n\"\\\\$1\")}};var Y={},Cc={};Y.ka=function(a,",
-    "b,c){try{var d=Ac.i(\"a\",b)}catch(e){d=C(z(b),\"A\",null,b)}return sa",
+    "replace(/(^|[^\\d\\p{L}\\p{S}])([\\p{Ll}|\\p{S}])/gu,function(e,f,g){r",
+    "eturn f+g.toUpperCase()}):\"uppercase\"==d?a=a.toUpperCase():\"lowerca",
+    "se\"==d&&(a=a.toLowerCase());c=b.pop()||\"\";wa(c)&&0==a.lastIndexOf(",
+    "\" \",0)&&(a=a.substr(1));\nb.push(c+a)}function nc(a){var b=1,c=W(a,",
+    "\"opacity\");c&&(b=Number(c));(a=hc(a))&&(b*=nc(a));return b}\nfunctio",
+    "n yc(a,b,c,d,e){if(3==a.nodeType&&c)xc(a,b,d,e);else if(T(a))if(T(a,\"",
+    "CONTENT\")||T(a,\"SLOT\")){for(var f=a;f.parentNode;)f=f.parentNode;f ",
+    "instanceof ShadowRoot?(a=T(a,\"CONTENT\")?a.getDistributedNodes():a.as",
+    "signedNodes(),w(a,function(g){yc(g,b,c,d,e)})):tc(a,b)}else if(T(a,\"S",
+    "HADOW\")){for(f=a;f.parentNode;)f=f.parentNode;if(f instanceof ShadowR",
+    "oot&&(a=f))for(a=a.olderShadowRoot;a;)w(a.childNodes,function(g){yc(g,",
+    "b,c,d,e)}),a=a.olderShadowRoot}else tc(a,b)}\nfunction tc(a,b){a.shado",
+    "wRoot&&w(a.shadowRoot.childNodes,function(c){yc(c,b,!0,null,null)});vc",
+    "(a,b,function(c,d,e,f,g){var h=null;1==c.nodeType?h=c:3==c.nodeType&&(",
+    "h=c);null!=h&&(null!=h.assignedSlot||h.getDestinationInsertionPoints&&",
+    "0<h.getDestinationInsertionPoints().length)||yc(c,d,e,f,g)})};var zc={",
+    "K:function(a){return!(!a.querySelectorAll||!a.querySelector)},o:functi",
+    "on(a,b){if(!a)throw new R(32,\"No class name specified\");a=xa(a);if(-",
+    "1!==a.indexOf(\" \"))throw new R(32,\"Compound class names not permitt",
+    "ed\");if(zc.K(b))try{return b.querySelector(\".\"+a.replace(/\\./g,\"",
+    "\\\\.\"))||null}catch(c){throw new R(32,\"An invalid or illegal class ",
+    "name was specified\");}a=C(z(b),\"*\",a,b);return a.length?a[0]:null},",
+    "i:function(a,b){if(!a)throw new R(32,\"No class name specified\");a=xa",
+    "(a);if(-1!==a.indexOf(\" \"))throw new R(32,\n\"Compound class names n",
+    "ot permitted\");if(zc.K(b))try{return b.querySelectorAll(\".\"+a.repla",
+    "ce(/\\./g,\"\\\\.\"))}catch(c){throw new R(32,\"An invalid or illegal ",
+    "class name was specified\");}return C(z(b),\"*\",a,b)}};var Ac={o:func",
+    "tion(a,b){q(b.querySelector);if(!a)throw new R(32,\"No selector specif",
+    "ied\");a=xa(a);try{var c=b.querySelector(a)}catch(d){throw new R(32,\"",
+    "An invalid or illegal selector was specified\");}return c&&1==c.nodeTy",
+    "pe?c:null},i:function(a,b){q(b.querySelectorAll);if(!a)throw new R(32,",
+    "\"No selector specified\");a=xa(a);try{return b.querySelectorAll(a)}ca",
+    "tch(c){throw new R(32,\"An invalid or illegal selector was specified\"",
+    ");}}};var Bc={K:function(a,b){return!(!a.querySelectorAll||!a.querySel",
+    "ector)&&!/^\\d.*/.test(b)},o:function(a,b){var c=z(b),d=n(a)?c.C.getEl",
+    "ementById(a):a;return d?cc(d,\"id\")==a&&b!=d&&Ia(b,d)?d:sa(C(c,\"*\")",
+    ",function(e){return cc(e,\"id\")==a&&b!=e&&Ia(b,e)}):null},i:function(",
+    "a,b){if(!a)return[];if(Bc.K(b,a))try{return b.querySelectorAll(\"#\"+B",
+    "c.ra(a))}catch(c){return[]}b=C(z(b),\"*\",null,b);return oa(b,function",
+    "(c){return cc(c,\"id\")==a})},ra:function(a){return a.replace(/([\\s'",
+    "\"\\\\#.:;,!?+<>=~*^$|%&@`{}\\-\\/\\[\\]\\(\\)])/g,\n\"\\\\$1\")}};var",
+    " Y={},Cc={};Y.ka=function(a,b,c){try{var d=Ac.i(\"a\",b)}catch(e){d=C(",
+    "z(b),\"A\",null,b)}return sa(d,function(e){e=sc(e);e=e.replace(/^[\\s]",
+    "+|[\\s]+$/g,\"\");return c&&-1!=e.indexOf(a)||e==a})};Y.fa=function(a,",
+    "b,c){try{var d=Ac.i(\"a\",b)}catch(e){d=C(z(b),\"A\",null,b)}return oa",
     "(d,function(e){e=sc(e);e=e.replace(/^[\\s]+|[\\s]+$/g,\"\");return c&&",
-    "-1!=e.indexOf(a)||e==a})};Y.fa=function(a,b,c){try{var d=Ac.i(\"a\",b)",
-    "}catch(e){d=C(z(b),\"A\",null,b)}return oa(d,function(e){e=sc(e);e=e.r",
-    "eplace(/^[\\s]+|[\\s]+$/g,\"\");return c&&-1!=e.indexOf(a)||e==a})};Y.",
-    "o=function(a,b){return Y.ka(a,b,!1)};Y.i=function(a,b){return Y.fa(a,b",
-    ",!1)};Cc.o=function(a,b){return Y.ka(a,b,!0)};\nCc.i=function(a,b){ret",
-    "urn Y.fa(a,b,!0)};var Z={P:function(a,b){return function(c){var d=Z.X(",
-    "a);d=kc(d);c=kc(c);return b.call(null,d,c)}},pa:function(a){return Z.P",
-    "(a,function(b,c){return c.top+c.height<b.top})},qa:function(a){return ",
-    "Z.P(a,function(b,c){return b.top+b.height<c.top})},ta:function(a){retu",
-    "rn Z.P(a,function(b,c){return c.left+c.width<b.left})},Ca:function(a){",
-    "return Z.P(a,function(b,c){return b.left+b.width<c.left})},ua:function",
-    "(a,b){if(b)var c=b;else p(a.distance)&&(c=a.distance,delete a.distance",
-    ");c||(c=50);return function(d){var e=\nZ.X(a);if(e===d)return!1;e=kc(e",
-    ");d=kc(d);var f=d.left+d.width,g=e.top-e.height,h=d.top-d.height;retur",
-    "n Math.abs(e.left+e.width-d.left)<=c||Math.abs(f-e.left)<=c?Math.abs(g",
-    "-d.top)<=c||Math.abs(h-e.top)<=c:!1}},X:function(a){if(fa(a)&&1==a.nod",
-    "eType)return a;if(q(a))return Z.X(a.call(null));if(fa(a)){var b=Dc(a);",
-    "if(!b)throw new R(7,\"No element has been found by \"+JSON.stringify(a",
-    "));return b}throw new R(61,\"Selector is of wrong type: \"+JSON.string",
-    "ify(a));}};\nZ.oa={left:Z.ta,right:Z.Ca,above:Z.pa,below:Z.qa,near:Z.u",
-    "a};Z.sa=function(a,b){var c=[];w(a,function(d){d&&ra(b,function(e){var",
-    " f=e.kind,g=Z.oa[f];if(!g)throw new R(61,\"Cannot find filter suitable",
-    " for \"+f);return g.apply(null,e.args)(d)},null)&&c.push(d)},null);ret",
-    "urn c};Z.o=function(a,b){a=Z.i(a,b);return 0==a.length?null:a[0]};\nZ.",
-    "i=function(a,b){if(!a.hasOwnProperty(\"root\")||!a.hasOwnProperty(\"fi",
-    "lters\"))throw new R(61,\"Locator not suitable for relative locators: ",
-    "\"+JSON.stringify(a));if(!ea(a.filters))throw new R(61,\"Targets shoul",
-    "d be an array: \"+JSON.stringify(a));b=T(a.root)?[a.root]:Ec(a.root,b)",
-    ";return 0==b.length?[]:Z.sa(b,a.filters)};var Fc={o:function(a,b){if(",
-    "\"\"===a)throw new R(32,'Unable to locate an element with the tagName ",
-    "\"\"');return b.getElementsByTagName(a)[0]||null},i:function(a,b){if(",
-    "\"\"===a)throw new R(32,'Unable to locate an element with the tagName ",
-    "\"\"');return b.getElementsByTagName(a)}};var Gc={className:zc,\"class",
-    " name\":zc,css:Ac,\"css selector\":Ac,relative:Z,id:Bc,linkText:Y,\"li",
-    "nk text\":Y,name:{o:function(a,b){b=C(z(b),\"*\",null,b);return sa(b,f",
-    "unction(c){return cc(c,\"name\")==a})},i:function(a,b){b=C(z(b),\"*\",",
-    "null,b);return oa(b,function(c){return cc(c,\"name\")==a})}},partialLi",
-    "nkText:Cc,\"partial link text\":Cc,tagName:Fc,\"tag name\":Fc,xpath:U}",
-    ";function Hc(a){for(var b in a)if(a.hasOwnProperty(b))return b;return ",
-    "null}\nfunction Dc(a,b){var c=Hc(a);if(c){var d=Gc[c];if(d&&q(d.o))ret",
-    "urn d.o(a[c],b||Vb.document)}throw new R(61,\"Unsupported locator stra",
-    "tegy: \"+c);}function Ec(a,b){var c=Hc(a);if(c){var d=Gc[c];if(d&&q(d.",
-    "i))return d.i(a[c],b||Vb.document)}throw new R(61,\"Unsupported locato",
-    "r strategy: \"+c);};var Ic=\"function\"===typeof ShadowRoot;ca(\"_\",f",
-    "unction(a,b){var c=Dc(a,b);if(c)return c;if(Ic&&b){for(c=b;c.parentNod",
-    "e;)c=c.parentNode;if(c instanceof ShadowRoot&&(c=Ec(a,b)[0]))return c}",
-    "return null});; return this._.apply(null,arguments);}).apply({navigato",
-    "r:typeof window!='undefined'?window.navigator:null,document:typeof win",
-    "dow!='undefined'?window.document:null}, arguments);}\n",
+    "-1!=e.indexOf(a)||e==a})};Y.o=function(a,b){return Y.ka(a,b,!1)};Y.i=f",
+    "unction(a,b){return Y.fa(a,b,!1)};Cc.o=function(a,b){return Y.ka(a,b,!",
+    "0)};\nCc.i=function(a,b){return Y.fa(a,b,!0)};var Z={P:function(a,b){r",
+    "eturn function(c){var d=Z.X(a);d=kc(d);c=kc(c);return b.call(null,d,c)",
+    "}},pa:function(a){return Z.P(a,function(b,c){return c.top+c.height<b.t",
+    "op})},qa:function(a){return Z.P(a,function(b,c){return b.top+b.height<",
+    "c.top})},ta:function(a){return Z.P(a,function(b,c){return c.left+c.wid",
+    "th<b.left})},Ca:function(a){return Z.P(a,function(b,c){return b.left+b",
+    ".width<c.left})},ua:function(a,b){if(b)var c=b;else p(a.distance)&&(c=",
+    "a.distance,delete a.distance);c||(c=50);return function(d){var e=\nZ.X",
+    "(a);if(e===d)return!1;e=kc(e);d=kc(d);var f=d.left+d.width,g=e.top-e.h",
+    "eight,h=d.top-d.height;return Math.abs(e.left+e.width-d.left)<=c||Math",
+    ".abs(f-e.left)<=c?Math.abs(g-d.top)<=c||Math.abs(h-e.top)<=c:!1}},X:fu",
+    "nction(a){if(fa(a)&&1==a.nodeType)return a;if(q(a))return Z.X(a.call(n",
+    "ull));if(fa(a)){var b=Dc(a);if(!b)throw new R(7,\"No element has been ",
+    "found by \"+JSON.stringify(a));return b}throw new R(61,\"Selector is o",
+    "f wrong type: \"+JSON.stringify(a));}};\nZ.oa={left:Z.ta,right:Z.Ca,ab",
+    "ove:Z.pa,below:Z.qa,near:Z.ua};Z.sa=function(a,b){var c=[];w(a,functio",
+    "n(d){d&&ra(b,function(e){var f=e.kind,g=Z.oa[f];if(!g)throw new R(61,",
+    "\"Cannot find filter suitable for \"+f);return g.apply(null,e.args)(d)",
+    "},null)&&c.push(d)},null);return c};Z.o=function(a,b){a=Z.i(a,b);retur",
+    "n 0==a.length?null:a[0]};\nZ.i=function(a,b){if(!a.hasOwnProperty(\"ro",
+    "ot\")||!a.hasOwnProperty(\"filters\"))throw new R(61,\"Locator not sui",
+    "table for relative locators: \"+JSON.stringify(a));if(!ea(a.filters))t",
+    "hrow new R(61,\"Targets should be an array: \"+JSON.stringify(a));b=T(",
+    "a.root)?[a.root]:Ec(a.root,b);return 0==b.length?[]:Z.sa(b,a.filters)}",
+    ";var Fc={o:function(a,b){if(\"\"===a)throw new R(32,'Unable to locate ",
+    "an element with the tagName \"\"');return b.getElementsByTagName(a)[0]",
+    "||null},i:function(a,b){if(\"\"===a)throw new R(32,'Unable to locate a",
+    "n element with the tagName \"\"');return b.getElementsByTagName(a)}};v",
+    "ar Gc={className:zc,\"class name\":zc,css:Ac,\"css selector\":Ac,relat",
+    "ive:Z,id:Bc,linkText:Y,\"link text\":Y,name:{o:function(a,b){b=C(z(b),",
+    "\"*\",null,b);return sa(b,function(c){return cc(c,\"name\")==a})},i:fu",
+    "nction(a,b){b=C(z(b),\"*\",null,b);return oa(b,function(c){return cc(c",
+    ",\"name\")==a})}},partialLinkText:Cc,\"partial link text\":Cc,tagName:",
+    "Fc,\"tag name\":Fc,xpath:U};function Hc(a){for(var b in a)if(a.hasOwnP",
+    "roperty(b))return b;return null}\nfunction Dc(a,b){var c=Hc(a);if(c){v",
+    "ar d=Gc[c];if(d&&q(d.o))return d.o(a[c],b||Vb.document)}throw new R(61",
+    ",\"Unsupported locator strategy: \"+c);}function Ec(a,b){var c=Hc(a);i",
+    "f(c){var d=Gc[c];if(d&&q(d.i))return d.i(a[c],b||Vb.document)}throw ne",
+    "w R(61,\"Unsupported locator strategy: \"+c);};var Ic=\"function\"===t",
+    "ypeof ShadowRoot;ca(\"_\",function(a,b){var c=Dc(a,b);if(c)return c;if",
+    "(Ic&&b){for(c=b;c.parentNode;)c=c.parentNode;if(c instanceof ShadowRoo",
+    "t&&(c=Ec(a,b)[0]))return c}return null});; return this._.apply(null,ar",
+    "guments);}).apply({navigator:typeof window!='undefined'?window.navigat",
+    "or:null,document:typeof window!='undefined'?window.document:null}, arg",
+    "uments);}\n",
     NULL
 };
 
@@ -4060,78 +4061,79 @@
     "g,\"\\n\");if(\"normal\"==c||\"nowrap\"==c)a=a.replace(/\\n/g,\" \");a",
     "=\"pre\"==c||\"pre-wrap\"==c?a.replace(/[ \\f\\t\\v\\u2028\\u2029]/g,",
     "\"\\u00a0\"):a.replace(/[ \\f\\t\\v\\u2028\\u2029]+/g,\" \");\"capital",
-    "ize\"==d?a=a.replace(/(^|\\s|\\b)(\\S)/g,function(e,f,g){return f+g.to",
-    "UpperCase()}):\"uppercase\"==d?a=a.toUpperCase():\"lowercase\"==d&&(a=",
-    "a.toLowerCase());c=b.pop()||\"\";wa(c)&&0==a.lastIndexOf(\" \",0)&&(a=",
-    "a.substr(1));b.push(c+a)}\nfunction pc(a){var b=1,c=W(a,\"opacity\");c",
-    "&&(b=Number(c));(a=jc(a))&&(b*=pc(a));return b}\nfunction Ac(a,b,c,d,e",
-    "){if(3==a.nodeType&&c)zc(a,b,d,e);else if(T(a))if(T(a,\"CONTENT\")||T(",
-    "a,\"SLOT\")){for(var f=a;f.parentNode;)f=f.parentNode;f instanceof Sha",
-    "dowRoot?(a=T(a,\"CONTENT\")?a.getDistributedNodes():a.assignedNodes(),",
-    "w(a,function(g){Ac(g,b,c,d,e)})):vc(a,b)}else if(T(a,\"SHADOW\")){for(",
-    "f=a;f.parentNode;)f=f.parentNode;if(f instanceof ShadowRoot&&(a=f))for",
-    "(a=a.olderShadowRoot;a;)w(a.childNodes,function(g){Ac(g,b,c,d,e)}),a=a",
-    ".olderShadowRoot}else vc(a,b)}\nfunction vc(a,b){a.shadowRoot&&w(a.sha",
-    "dowRoot.childNodes,function(c){Ac(c,b,!0,null,null)});xc(a,b,function(",
-    "c,d,e,f,g){var h=null;1==c.nodeType?h=c:3==c.nodeType&&(h=c);null!=h&&",
-    "(null!=h.assignedSlot||h.getDestinationInsertionPoints&&0<h.getDestina",
-    "tionInsertionPoints().length)||Ac(c,d,e,f,g)})};var Bc={K:function(a,b",
-    "){return!(!a.querySelectorAll||!a.querySelector)&&!/^\\d.*/.test(b)},o",
-    ":function(a,b){var c=z(b),d=n(a)?c.C.getElementById(a):a;return d?ec(d",
-    ",\"id\")==a&&b!=d&&Ia(b,d)?d:sa(C(c,\"*\"),function(e){return ec(e,\"i",
-    "d\")==a&&b!=e&&Ia(b,e)}):null},i:function(a,b){if(!a)return[];if(Bc.K(",
-    "b,a))try{return b.querySelectorAll(\"#\"+Bc.ra(a))}catch(c){return[]}b",
-    "=C(z(b),\"*\",null,b);return oa(b,function(c){return ec(c,\"id\")==a})",
-    "},ra:function(a){return a.replace(/([\\s'\"\\\\#.:;,!?+<>=~*^$|%&@`{}",
-    "\\-\\/\\[\\]\\(\\)])/g,\n\"\\\\$1\")}};var Y={},Cc={};Y.ka=function(a,",
-    "b,c){try{var d=Yb.i(\"a\",b)}catch(e){d=C(z(b),\"A\",null,b)}return sa",
-    "(d,function(e){e=uc(e);e=e.replace(/^[\\s]+|[\\s]+$/g,\"\");return c&&",
-    "-1!=e.indexOf(a)||e==a})};Y.fa=function(a,b,c){try{var d=Yb.i(\"a\",b)",
-    "}catch(e){d=C(z(b),\"A\",null,b)}return oa(d,function(e){e=uc(e);e=e.r",
-    "eplace(/^[\\s]+|[\\s]+$/g,\"\");return c&&-1!=e.indexOf(a)||e==a})};Y.",
-    "o=function(a,b){return Y.ka(a,b,!1)};Y.i=function(a,b){return Y.fa(a,b",
-    ",!1)};Cc.o=function(a,b){return Y.ka(a,b,!0)};\nCc.i=function(a,b){ret",
-    "urn Y.fa(a,b,!0)};var Z={P:function(a,b){return function(c){var d=Z.X(",
-    "a);d=mc(d);c=mc(c);return b.call(null,d,c)}},pa:function(a){return Z.P",
-    "(a,function(b,c){return c.top+c.height<b.top})},qa:function(a){return ",
-    "Z.P(a,function(b,c){return b.top+b.height<c.top})},ta:function(a){retu",
-    "rn Z.P(a,function(b,c){return c.left+c.width<b.left})},Ca:function(a){",
-    "return Z.P(a,function(b,c){return b.left+b.width<c.left})},ua:function",
-    "(a,b){if(b)var c=b;else p(a.distance)&&(c=a.distance,delete a.distance",
-    ");c||(c=50);return function(d){var e=\nZ.X(a);if(e===d)return!1;e=mc(e",
-    ");d=mc(d);var f=d.left+d.width,g=e.top-e.height,h=d.top-d.height;retur",
-    "n Math.abs(e.left+e.width-d.left)<=c||Math.abs(f-e.left)<=c?Math.abs(g",
-    "-d.top)<=c||Math.abs(h-e.top)<=c:!1}},X:function(a){if(fa(a)&&1==a.nod",
-    "eType)return a;if(q(a))return Z.X(a.call(null));if(fa(a)){var b;a:{if(",
-    "b=Dc(a)){var c=Ec[b];if(c&&q(c.o)){b=c.o(a[b],Vb.document);break a}}th",
-    "row new R(61,\"Unsupported locator strategy: \"+b);}if(!b)throw new R(",
-    "7,\"No element has been found by \"+JSON.stringify(a));\nreturn b}thro",
-    "w new R(61,\"Selector is of wrong type: \"+JSON.stringify(a));}};Z.oa=",
-    "{left:Z.ta,right:Z.Ca,above:Z.pa,below:Z.qa,near:Z.ua};Z.sa=function(a",
-    ",b){var c=[];w(a,function(d){d&&ra(b,function(e){var f=e.kind,g=Z.oa[f",
-    "];if(!g)throw new R(61,\"Cannot find filter suitable for \"+f);return ",
-    "g.apply(null,e.args)(d)},null)&&c.push(d)},null);return c};Z.o=functio",
-    "n(a,b){a=Z.i(a,b);return 0==a.length?null:a[0]};\nZ.i=function(a,b){if",
-    "(!a.hasOwnProperty(\"root\")||!a.hasOwnProperty(\"filters\"))throw new",
-    " R(61,\"Locator not suitable for relative locators: \"+JSON.stringify(",
-    "a));if(!ea(a.filters))throw new R(61,\"Targets should be an array: \"+",
-    "JSON.stringify(a));b=T(a.root)?[a.root]:Fc(a.root,b);return 0==b.lengt",
-    "h?[]:Z.sa(b,a.filters)};var Gc={o:function(a,b){if(\"\"===a)throw new ",
-    "R(32,'Unable to locate an element with the tagName \"\"');return b.get",
-    "ElementsByTagName(a)[0]||null},i:function(a,b){if(\"\"===a)throw new R",
-    "(32,'Unable to locate an element with the tagName \"\"');return b.getE",
-    "lementsByTagName(a)}};var Ec={className:Xb,\"class name\":Xb,css:Yb,\"",
-    "css selector\":Yb,relative:Z,id:Bc,linkText:Y,\"link text\":Y,name:{o:",
-    "function(a,b){b=C(z(b),\"*\",null,b);return sa(b,function(c){return ec",
-    "(c,\"name\")==a})},i:function(a,b){b=C(z(b),\"*\",null,b);return oa(b,",
-    "function(c){return ec(c,\"name\")==a})}},partialLinkText:Cc,\"partial ",
-    "link text\":Cc,tagName:Gc,\"tag name\":Gc,xpath:U};function Dc(a){for(",
-    "var b in a)if(a.hasOwnProperty(b))return b;return null}\nfunction Fc(a",
-    ",b){var c=Dc(a);if(c){var d=Ec[c];if(d&&q(d.i))return d.i(a[c],b||Vb.d",
-    "ocument)}throw new R(61,\"Unsupported locator strategy: \"+c);};ca(\"_",
-    "\",Fc);; return this._.apply(null,arguments);}).apply({navigator:typeo",
-    "f window!='undefined'?window.navigator:null,document:typeof window!='u",
-    "ndefined'?window.document:null}, arguments);}\n",
+    "ize\"==d?a=a.replace(/(^|[^\\d\\p{L}\\p{S}])([\\p{Ll}|\\p{S}])/gu,func",
+    "tion(e,f,g){return f+g.toUpperCase()}):\"uppercase\"==d?a=a.toUpperCas",
+    "e():\"lowercase\"==d&&(a=a.toLowerCase());c=b.pop()||\"\";wa(c)&&0==a.",
+    "lastIndexOf(\" \",0)&&(a=a.substr(1));\nb.push(c+a)}function pc(a){var",
+    " b=1,c=W(a,\"opacity\");c&&(b=Number(c));(a=jc(a))&&(b*=pc(a));return ",
+    "b}\nfunction Ac(a,b,c,d,e){if(3==a.nodeType&&c)zc(a,b,d,e);else if(T(a",
+    "))if(T(a,\"CONTENT\")||T(a,\"SLOT\")){for(var f=a;f.parentNode;)f=f.pa",
+    "rentNode;f instanceof ShadowRoot?(a=T(a,\"CONTENT\")?a.getDistributedN",
+    "odes():a.assignedNodes(),w(a,function(g){Ac(g,b,c,d,e)})):vc(a,b)}else",
+    " if(T(a,\"SHADOW\")){for(f=a;f.parentNode;)f=f.parentNode;if(f instanc",
+    "eof ShadowRoot&&(a=f))for(a=a.olderShadowRoot;a;)w(a.childNodes,functi",
+    "on(g){Ac(g,b,c,d,e)}),a=a.olderShadowRoot}else vc(a,b)}\nfunction vc(a",
+    ",b){a.shadowRoot&&w(a.shadowRoot.childNodes,function(c){Ac(c,b,!0,null",
+    ",null)});xc(a,b,function(c,d,e,f,g){var h=null;1==c.nodeType?h=c:3==c.",
+    "nodeType&&(h=c);null!=h&&(null!=h.assignedSlot||h.getDestinationInsert",
+    "ionPoints&&0<h.getDestinationInsertionPoints().length)||Ac(c,d,e,f,g)}",
+    ")};var Bc={K:function(a,b){return!(!a.querySelectorAll||!a.querySelect",
+    "or)&&!/^\\d.*/.test(b)},o:function(a,b){var c=z(b),d=n(a)?c.C.getEleme",
+    "ntById(a):a;return d?ec(d,\"id\")==a&&b!=d&&Ia(b,d)?d:sa(C(c,\"*\"),fu",
+    "nction(e){return ec(e,\"id\")==a&&b!=e&&Ia(b,e)}):null},i:function(a,b",
+    "){if(!a)return[];if(Bc.K(b,a))try{return b.querySelectorAll(\"#\"+Bc.r",
+    "a(a))}catch(c){return[]}b=C(z(b),\"*\",null,b);return oa(b,function(c)",
+    "{return ec(c,\"id\")==a})},ra:function(a){return a.replace(/([\\s'\"",
+    "\\\\#.:;,!?+<>=~*^$|%&@`{}\\-\\/\\[\\]\\(\\)])/g,\n\"\\\\$1\")}};var Y",
+    "={},Cc={};Y.ka=function(a,b,c){try{var d=Yb.i(\"a\",b)}catch(e){d=C(z(",
+    "b),\"A\",null,b)}return sa(d,function(e){e=uc(e);e=e.replace(/^[\\s]+|",
+    "[\\s]+$/g,\"\");return c&&-1!=e.indexOf(a)||e==a})};Y.fa=function(a,b,",
+    "c){try{var d=Yb.i(\"a\",b)}catch(e){d=C(z(b),\"A\",null,b)}return oa(d",
+    ",function(e){e=uc(e);e=e.replace(/^[\\s]+|[\\s]+$/g,\"\");return c&&-1",
+    "!=e.indexOf(a)||e==a})};Y.o=function(a,b){return Y.ka(a,b,!1)};Y.i=fun",
+    "ction(a,b){return Y.fa(a,b,!1)};Cc.o=function(a,b){return Y.ka(a,b,!0)",
+    "};\nCc.i=function(a,b){return Y.fa(a,b,!0)};var Z={P:function(a,b){ret",
+    "urn function(c){var d=Z.X(a);d=mc(d);c=mc(c);return b.call(null,d,c)}}",
+    ",pa:function(a){return Z.P(a,function(b,c){return c.top+c.height<b.top",
+    "})},qa:function(a){return Z.P(a,function(b,c){return b.top+b.height<c.",
+    "top})},ta:function(a){return Z.P(a,function(b,c){return c.left+c.width",
+    "<b.left})},Ca:function(a){return Z.P(a,function(b,c){return b.left+b.w",
+    "idth<c.left})},ua:function(a,b){if(b)var c=b;else p(a.distance)&&(c=a.",
+    "distance,delete a.distance);c||(c=50);return function(d){var e=\nZ.X(a",
+    ");if(e===d)return!1;e=mc(e);d=mc(d);var f=d.left+d.width,g=e.top-e.hei",
+    "ght,h=d.top-d.height;return Math.abs(e.left+e.width-d.left)<=c||Math.a",
+    "bs(f-e.left)<=c?Math.abs(g-d.top)<=c||Math.abs(h-e.top)<=c:!1}},X:func",
+    "tion(a){if(fa(a)&&1==a.nodeType)return a;if(q(a))return Z.X(a.call(nul",
+    "l));if(fa(a)){var b;a:{if(b=Dc(a)){var c=Ec[b];if(c&&q(c.o)){b=c.o(a[b",
+    "],Vb.document);break a}}throw new R(61,\"Unsupported locator strategy:",
+    " \"+b);}if(!b)throw new R(7,\"No element has been found by \"+JSON.str",
+    "ingify(a));\nreturn b}throw new R(61,\"Selector is of wrong type: \"+J",
+    "SON.stringify(a));}};Z.oa={left:Z.ta,right:Z.Ca,above:Z.pa,below:Z.qa,",
+    "near:Z.ua};Z.sa=function(a,b){var c=[];w(a,function(d){d&&ra(b,functio",
+    "n(e){var f=e.kind,g=Z.oa[f];if(!g)throw new R(61,\"Cannot find filter ",
+    "suitable for \"+f);return g.apply(null,e.args)(d)},null)&&c.push(d)},n",
+    "ull);return c};Z.o=function(a,b){a=Z.i(a,b);return 0==a.length?null:a[",
+    "0]};\nZ.i=function(a,b){if(!a.hasOwnProperty(\"root\")||!a.hasOwnPrope",
+    "rty(\"filters\"))throw new R(61,\"Locator not suitable for relative lo",
+    "cators: \"+JSON.stringify(a));if(!ea(a.filters))throw new R(61,\"Targe",
+    "ts should be an array: \"+JSON.stringify(a));b=T(a.root)?[a.root]:Fc(a",
+    ".root,b);return 0==b.length?[]:Z.sa(b,a.filters)};var Gc={o:function(a",
+    ",b){if(\"\"===a)throw new R(32,'Unable to locate an element with the t",
+    "agName \"\"');return b.getElementsByTagName(a)[0]||null},i:function(a,",
+    "b){if(\"\"===a)throw new R(32,'Unable to locate an element with the ta",
+    "gName \"\"');return b.getElementsByTagName(a)}};var Ec={className:Xb,",
+    "\"class name\":Xb,css:Yb,\"css selector\":Yb,relative:Z,id:Bc,linkText",
+    ":Y,\"link text\":Y,name:{o:function(a,b){b=C(z(b),\"*\",null,b);return",
+    " sa(b,function(c){return ec(c,\"name\")==a})},i:function(a,b){b=C(z(b)",
+    ",\"*\",null,b);return oa(b,function(c){return ec(c,\"name\")==a})}},pa",
+    "rtialLinkText:Cc,\"partial link text\":Cc,tagName:Gc,\"tag name\":Gc,x",
+    "path:U};function Dc(a){for(var b in a)if(a.hasOwnProperty(b))return b;",
+    "return null}\nfunction Fc(a,b){var c=Dc(a);if(c){var d=Ec[c];if(d&&q(d",
+    ".i))return d.i(a[c],b||Vb.document)}throw new R(61,\"Unsupported locat",
+    "or strategy: \"+c);};ca(\"_\",Fc);; return this._.apply(null,arguments",
+    ");}).apply({navigator:typeof window!='undefined'?window.navigator:null",
+    ",document:typeof window!='undefined'?window.document:null}, arguments)",
+    ";}\n",
     NULL
 };
 
@@ -10807,74 +10809,74 @@
     "\"\");a=a.replace(/(\\r\\n|\\r|\\n)/g,\"\\n\");if(\"normal\"==c||\"now",
     "rap\"==c)a=a.replace(/\\n/g,\" \");a=\"pre\"==c||\"pre-wrap\"==c?a.rep",
     "lace(/[ \\f\\t\\v\\u2028\\u2029]/g,\"\\u00a0\"):a.replace(/[ \\f\\t\\v",
-    "\\u2028\\u2029]+/g,\" \");\"capitalize\"==d?a=a.replace(/(^|\\s|\\b)(",
-    "\\S)/g,function(e,f,g){return f+g.toUpperCase()}):\"uppercase\"==d?a=a",
-    ".toUpperCase():\"lowercase\"==d&&(a=a.toLowerCase());c=b.pop()||\"\";q",
-    "a(c)&&0==a.lastIndexOf(\" \",0)&&(a=a.substr(1));b.push(c+a)}\nfunctio",
-    "n gc(a){var b=1,c=X(a,\"opacity\");c&&(b=Number(c));(a=ac(a))&&(b*=gc(",
-    "a));return b}\nfunction pc(a,b,c,d,e){if(3==a.nodeType&&c)oc(a,b,d,e);",
-    "else if(T(a))if(T(a,\"CONTENT\")||T(a,\"SLOT\")){for(var f=a;f.parentN",
-    "ode;)f=f.parentNode;f instanceof ShadowRoot?(a=T(a,\"CONTENT\")?a.getD",
-    "istributedNodes():a.assignedNodes(),u(a,function(g){pc(g,b,c,d,e)})):q",
-    "c(a,b)}else if(T(a,\"SHADOW\")){for(f=a;f.parentNode;)f=f.parentNode;i",
-    "f(f instanceof ShadowRoot&&(a=f))for(a=a.olderShadowRoot;a;)u(a.childN",
-    "odes,function(g){pc(g,b,c,d,e)}),a=a.olderShadowRoot}else qc(a,b)}\nfu",
-    "nction qc(a,b){a.shadowRoot&&u(a.shadowRoot.childNodes,function(c){pc(",
-    "c,b,!0,null,null)});lc(a,b,function(c,d,e,f,g){var k=null;1==c.nodeTyp",
-    "e?k=c:3==c.nodeType&&(k=c);null!=k&&(null!=k.assignedSlot||k.getDestin",
-    "ationInsertionPoints&&0<k.getDestinationInsertionPoints().length)||pc(",
-    "c,d,e,f,g)})};function rc(a,b){this.C={};this.j=[];this.F=0;var c=argu",
-    "ments.length;if(1<c){if(c%2)throw Error(\"Uneven number of arguments\"",
-    ");for(var d=0;d<c;d+=2)this.set(arguments[d],arguments[d+1])}else a&&t",
-    "his.addAll(a)}function sc(a){tc(a);return a.j.concat()}h=rc.prototype;",
-    "h.clear=function(){this.C={};this.F=this.j.length=0};h.remove=function",
-    "(a){return Object.prototype.hasOwnProperty.call(this.C,a)?(delete this",
-    ".C[a],this.F--,this.j.length>2*this.F&&tc(this),!0):!1};\nfunction tc(",
-    "a){if(a.F!=a.j.length){for(var b=0,c=0;b<a.j.length;){var d=a.j[b];Obj",
-    "ect.prototype.hasOwnProperty.call(a.C,d)&&(a.j[c++]=d);b++}a.j.length=",
-    "c}if(a.F!=a.j.length){var e={};for(c=b=0;b<a.j.length;)d=a.j[b],Object",
-    ".prototype.hasOwnProperty.call(e,d)||(a.j[c++]=d,e[d]=1),b++;a.j.lengt",
-    "h=c}}h.get=function(a,b){return Object.prototype.hasOwnProperty.call(t",
-    "his.C,a)?this.C[a]:b};h.set=function(a,b){Object.prototype.hasOwnPrope",
-    "rty.call(this.C,a)||(this.F++,this.j.push(a));this.C[a]=b};\nh.addAll=",
-    "function(a){if(a instanceof rc)for(var b=sc(a),c=0;c<b.length;c++)this",
-    ".set(b[c],a.get(b[c]));else for(b in a)this.set(b,a[b])};h.forEach=fun",
-    "ction(a,b){for(var c=sc(this),d=0;d<c.length;d++){var e=c[d],f=this.ge",
-    "t(e);a.call(b,f,e,this)}};h.clone=function(){return new rc(this)};var ",
-    "uc={};function Z(a,b,c){ea(a)&&(a=a.b);a=new vc(a);!b||b in uc&&!c||(u",
-    "c[b]={key:a,shift:!1},c&&(uc[c]={key:a,shift:!0}));return a}function v",
-    "c(a){this.code=a}Z(8);Z(9);Z(13);var wc=Z(16),xc=Z(17),yc=Z(18);Z(19);",
-    "Z(20);Z(27);Z(32,\" \");Z(33);Z(34);Z(35);Z(36);Z(37);Z(38);Z(39);Z(40",
-    ");Z(44);Z(45);Z(46);Z(48,\"0\",\")\");Z(49,\"1\",\"!\");Z(50,\"2\",\"@",
-    "\");Z(51,\"3\",\"#\");Z(52,\"4\",\"$\");Z(53,\"5\",\"%\");Z(54,\"6\",",
-    "\"^\");Z(55,\"7\",\"&\");Z(56,\"8\",\"*\");Z(57,\"9\",\"(\");Z(65,\"a",
-    "\",\"A\");Z(66,\"b\",\"B\");Z(67,\"c\",\"C\");Z(68,\"d\",\"D\");\nZ(69",
-    ",\"e\",\"E\");Z(70,\"f\",\"F\");Z(71,\"g\",\"G\");Z(72,\"h\",\"H\");Z(",
-    "73,\"i\",\"I\");Z(74,\"j\",\"J\");Z(75,\"k\",\"K\");Z(76,\"l\",\"L\");",
-    "Z(77,\"m\",\"M\");Z(78,\"n\",\"N\");Z(79,\"o\",\"O\");Z(80,\"p\",\"P\"",
-    ");Z(81,\"q\",\"Q\");Z(82,\"r\",\"R\");Z(83,\"s\",\"S\");Z(84,\"t\",\"T",
-    "\");Z(85,\"u\",\"U\");Z(86,\"v\",\"V\");Z(87,\"w\",\"W\");Z(88,\"x\",",
-    "\"X\");Z(89,\"y\",\"Y\");Z(90,\"z\",\"Z\");var zc=Z(wa?{c:91,b:91}:va?",
-    "{c:224,b:91}:{c:0,b:91});Z(wa?{c:92,b:92}:va?{c:224,b:93}:{c:0,b:92});",
-    "Z(wa?{c:93,b:93}:va?{c:0,b:0}:{c:93,b:null});Z({c:96,b:96},\"0\");Z({c",
-    ":97,b:97},\"1\");\nZ({c:98,b:98},\"2\");Z({c:99,b:99},\"3\");Z({c:100,",
-    "b:100},\"4\");Z({c:101,b:101},\"5\");Z({c:102,b:102},\"6\");Z({c:103,b",
-    ":103},\"7\");Z({c:104,b:104},\"8\");Z({c:105,b:105},\"9\");Z({c:106,b:",
-    "106},\"*\");Z({c:107,b:107},\"+\");Z({c:109,b:109},\"-\");Z({c:110,b:1",
-    "10},\".\");Z({c:111,b:111},\"/\");Z(144);Z(112);Z(113);Z(114);Z(115);Z",
-    "(116);Z(117);Z(118);Z(119);Z(120);Z(121);Z(122);Z(123);Z({c:107,b:187}",
-    ",\"=\",\"+\");Z(108,\",\");Z({c:109,b:189},\"-\",\"_\");Z(188,\",\",\"",
-    "<\");Z(190,\".\",\">\");Z(191,\"/\",\"?\");Z(192,\"`\",\"~\");Z(219,\"",
-    "[\",\"{\");\nZ(220,\"\\\\\",\"|\");Z(221,\"]\",\"}\");Z({c:59,b:186},",
-    "\";\",\":\");Z(222,\"'\",'\"');var Ac=new rc;Ac.set(1,wc);Ac.set(2,xc)",
-    ";Ac.set(4,yc);Ac.set(8,zc);(function(a){var b=new rc;u(sc(a),function(",
-    "c){b.set(a.get(c).code,c)});return b})(Ac);ba(\"_\",function(a){var b=",
-    "[];$b?qc(a,b):nc(a,b);var c=b;a=c.length;b=Array(a);c=m(c)?c.split(\"",
-    "\"):c;for(var d=0;d<a;d++)d in c&&(b[d]=kc.call(void 0,c[d]));return k",
-    "c(b.join(\"\\n\")).replace(/\\xa0/g,\" \")});; return this._.apply(nul",
-    "l,arguments);}).apply({navigator:typeof window!='undefined'?window.nav",
-    "igator:null,document:typeof window!='undefined'?window.document:null},",
-    " arguments);}\n",
+    "\\u2028\\u2029]+/g,\" \");\"capitalize\"==d?a=a.replace(/(^|[^\\d\\p{L",
+    "}\\p{S}])([\\p{Ll}|\\p{S}])/gu,function(e,f,g){return f+g.toUpperCase(",
+    ")}):\"uppercase\"==d?a=a.toUpperCase():\"lowercase\"==d&&(a=a.toLowerC",
+    "ase());c=b.pop()||\"\";qa(c)&&0==a.lastIndexOf(\" \",0)&&(a=a.substr(1",
+    "));\nb.push(c+a)}function gc(a){var b=1,c=X(a,\"opacity\");c&&(b=Numbe",
+    "r(c));(a=ac(a))&&(b*=gc(a));return b}\nfunction pc(a,b,c,d,e){if(3==a.",
+    "nodeType&&c)oc(a,b,d,e);else if(T(a))if(T(a,\"CONTENT\")||T(a,\"SLOT\"",
+    ")){for(var f=a;f.parentNode;)f=f.parentNode;f instanceof ShadowRoot?(a",
+    "=T(a,\"CONTENT\")?a.getDistributedNodes():a.assignedNodes(),u(a,functi",
+    "on(g){pc(g,b,c,d,e)})):qc(a,b)}else if(T(a,\"SHADOW\")){for(f=a;f.pare",
+    "ntNode;)f=f.parentNode;if(f instanceof ShadowRoot&&(a=f))for(a=a.older",
+    "ShadowRoot;a;)u(a.childNodes,function(g){pc(g,b,c,d,e)}),a=a.olderShad",
+    "owRoot}else qc(a,b)}\nfunction qc(a,b){a.shadowRoot&&u(a.shadowRoot.ch",
+    "ildNodes,function(c){pc(c,b,!0,null,null)});lc(a,b,function(c,d,e,f,g)",
+    "{var k=null;1==c.nodeType?k=c:3==c.nodeType&&(k=c);null!=k&&(null!=k.a",
+    "ssignedSlot||k.getDestinationInsertionPoints&&0<k.getDestinationInsert",
+    "ionPoints().length)||pc(c,d,e,f,g)})};function rc(a,b){this.C={};this.",
+    "j=[];this.F=0;var c=arguments.length;if(1<c){if(c%2)throw Error(\"Unev",
+    "en number of arguments\");for(var d=0;d<c;d+=2)this.set(arguments[d],a",
+    "rguments[d+1])}else a&&this.addAll(a)}function sc(a){tc(a);return a.j.",
+    "concat()}h=rc.prototype;h.clear=function(){this.C={};this.F=this.j.len",
+    "gth=0};h.remove=function(a){return Object.prototype.hasOwnProperty.cal",
+    "l(this.C,a)?(delete this.C[a],this.F--,this.j.length>2*this.F&&tc(this",
+    "),!0):!1};\nfunction tc(a){if(a.F!=a.j.length){for(var b=0,c=0;b<a.j.l",
+    "ength;){var d=a.j[b];Object.prototype.hasOwnProperty.call(a.C,d)&&(a.j",
+    "[c++]=d);b++}a.j.length=c}if(a.F!=a.j.length){var e={};for(c=b=0;b<a.j",
+    ".length;)d=a.j[b],Object.prototype.hasOwnProperty.call(e,d)||(a.j[c++]",
+    "=d,e[d]=1),b++;a.j.length=c}}h.get=function(a,b){return Object.prototy",
+    "pe.hasOwnProperty.call(this.C,a)?this.C[a]:b};h.set=function(a,b){Obje",
+    "ct.prototype.hasOwnProperty.call(this.C,a)||(this.F++,this.j.push(a));",
+    "this.C[a]=b};\nh.addAll=function(a){if(a instanceof rc)for(var b=sc(a)",
+    ",c=0;c<b.length;c++)this.set(b[c],a.get(b[c]));else for(b in a)this.se",
+    "t(b,a[b])};h.forEach=function(a,b){for(var c=sc(this),d=0;d<c.length;d",
+    "++){var e=c[d],f=this.get(e);a.call(b,f,e,this)}};h.clone=function(){r",
+    "eturn new rc(this)};var uc={};function Z(a,b,c){ea(a)&&(a=a.b);a=new v",
+    "c(a);!b||b in uc&&!c||(uc[b]={key:a,shift:!1},c&&(uc[c]={key:a,shift:!",
+    "0}));return a}function vc(a){this.code=a}Z(8);Z(9);Z(13);var wc=Z(16),",
+    "xc=Z(17),yc=Z(18);Z(19);Z(20);Z(27);Z(32,\" \");Z(33);Z(34);Z(35);Z(36",
+    ");Z(37);Z(38);Z(39);Z(40);Z(44);Z(45);Z(46);Z(48,\"0\",\")\");Z(49,\"1",
+    "\",\"!\");Z(50,\"2\",\"@\");Z(51,\"3\",\"#\");Z(52,\"4\",\"$\");Z(53,",
+    "\"5\",\"%\");Z(54,\"6\",\"^\");Z(55,\"7\",\"&\");Z(56,\"8\",\"*\");Z(5",
+    "7,\"9\",\"(\");Z(65,\"a\",\"A\");Z(66,\"b\",\"B\");Z(67,\"c\",\"C\");Z",
+    "(68,\"d\",\"D\");\nZ(69,\"e\",\"E\");Z(70,\"f\",\"F\");Z(71,\"g\",\"G",
+    "\");Z(72,\"h\",\"H\");Z(73,\"i\",\"I\");Z(74,\"j\",\"J\");Z(75,\"k\",",
+    "\"K\");Z(76,\"l\",\"L\");Z(77,\"m\",\"M\");Z(78,\"n\",\"N\");Z(79,\"o",
+    "\",\"O\");Z(80,\"p\",\"P\");Z(81,\"q\",\"Q\");Z(82,\"r\",\"R\");Z(83,",
+    "\"s\",\"S\");Z(84,\"t\",\"T\");Z(85,\"u\",\"U\");Z(86,\"v\",\"V\");Z(8",
+    "7,\"w\",\"W\");Z(88,\"x\",\"X\");Z(89,\"y\",\"Y\");Z(90,\"z\",\"Z\");v",
+    "ar zc=Z(wa?{c:91,b:91}:va?{c:224,b:91}:{c:0,b:91});Z(wa?{c:92,b:92}:va",
+    "?{c:224,b:93}:{c:0,b:92});Z(wa?{c:93,b:93}:va?{c:0,b:0}:{c:93,b:null})",
+    ";Z({c:96,b:96},\"0\");Z({c:97,b:97},\"1\");\nZ({c:98,b:98},\"2\");Z({c",
+    ":99,b:99},\"3\");Z({c:100,b:100},\"4\");Z({c:101,b:101},\"5\");Z({c:10",
+    "2,b:102},\"6\");Z({c:103,b:103},\"7\");Z({c:104,b:104},\"8\");Z({c:105",
+    ",b:105},\"9\");Z({c:106,b:106},\"*\");Z({c:107,b:107},\"+\");Z({c:109,",
+    "b:109},\"-\");Z({c:110,b:110},\".\");Z({c:111,b:111},\"/\");Z(144);Z(1",
+    "12);Z(113);Z(114);Z(115);Z(116);Z(117);Z(118);Z(119);Z(120);Z(121);Z(1",
+    "22);Z(123);Z({c:107,b:187},\"=\",\"+\");Z(108,\",\");Z({c:109,b:189},",
+    "\"-\",\"_\");Z(188,\",\",\"<\");Z(190,\".\",\">\");Z(191,\"/\",\"?\");",
+    "Z(192,\"`\",\"~\");Z(219,\"[\",\"{\");\nZ(220,\"\\\\\",\"|\");Z(221,\"",
+    "]\",\"}\");Z({c:59,b:186},\";\",\":\");Z(222,\"'\",'\"');var Ac=new rc",
+    ";Ac.set(1,wc);Ac.set(2,xc);Ac.set(4,yc);Ac.set(8,zc);(function(a){var ",
+    "b=new rc;u(sc(a),function(c){b.set(a.get(c).code,c)});return b})(Ac);b",
+    "a(\"_\",function(a){var b=[];$b?qc(a,b):nc(a,b);var c=b;a=c.length;b=A",
+    "rray(a);c=m(c)?c.split(\"\"):c;for(var d=0;d<a;d++)d in c&&(b[d]=kc.ca",
+    "ll(void 0,c[d]));return kc(b.join(\"\\n\")).replace(/\\xa0/g,\" \")});",
+    "; return this._.apply(null,arguments);}).apply({navigator:typeof windo",
+    "w!='undefined'?window.navigator:null,document:typeof window!='undefine",
+    "d'?window.document:null}, arguments);}\n",
     NULL
 };
 
diff --git a/third_party/webdriver/patch.diff b/third_party/webdriver/patch.diff
index 3f503600..f2799e718 100644
--- a/third_party/webdriver/patch.diff
+++ b/third_party/webdriver/patch.diff
@@ -1,5 +1,5 @@
 diff --git a/javascript/atoms/dom.js b/javascript/atoms/dom.js
-index 68dbdacc16..d3dbc883fd 100644
+index 68dbdacc16..d8519f518e 100644
 --- a/javascript/atoms/dom.js
 +++ b/javascript/atoms/dom.js
 @@ -587,14 +587,8 @@ bot.dom.isShown = function(elem, opt_ignoreOpacity) {
@@ -28,6 +28,15 @@
    }
  
    return bot.dom.isShown_(elem, !!opt_ignoreOpacity, displayed);
+@@ -1175,7 +1169,7 @@ bot.dom.appendVisibleTextLinesFromTextNode_ = function(textNode, lines,
+   }
+ 
+   if (textTransform == 'capitalize') {
+-    text = text.replace(/(^|\s|\b)(\S)/g, function() {
++    text = text.replace(/(^|[^\d\p{L}\p{S}])([\p{Ll}|\p{S}])/gu, function() {
+       return arguments[1] + arguments[2].toUpperCase();
+     });
+   } else if (textTransform == 'uppercase') {
 @@ -1270,13 +1264,6 @@ bot.dom.getOpacityNonIE_ = function(elem) {
  bot.dom.getParentNodeInComposedDom = function(node) {
    var /**@type {Node}*/ parent = node.parentNode;
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 9ca35d41..df5742e4 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -2075,7 +2075,7 @@
     ],
 
     'lacros_on_linux_release_trybot': [
-      'lacros_on_linux', 'release_trybot',
+      'lacros_on_linux', 'release_trybot', 'also_build_ash_chrome',
     ],
 
     'libfuzzer_asan_debug_bot': [
@@ -2860,6 +2860,10 @@
       'gn_args': 'use_ozone=true ozone_platform_wayland=true ozone_platform="wayland" use_gtk=false chromeos_is_browser_only=true'
     },
 
+    'also_build_ash_chrome': {
+      'gn_args': 'also_build_ash_chrome=true',
+    },
+
     'libfuzzer': { 'gn_args': 'use_libfuzzer=true' },
 
     'lsan': {
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json b/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json
index eda8a54..234b57f 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json
@@ -128,6 +128,7 @@
   },
   "linux-lacros-rel": {
     "gn_args": {
+      "also_build_ash_chrome": true,
       "chromeos_is_browser_only": true,
       "dcheck_always_on": true,
       "is_component_build": false,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
index d3c1e07a..3d0f18b8 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
@@ -409,6 +409,7 @@
   },
   "linux-lacros-fyi-rel": {
     "gn_args": {
+      "also_build_ash_chrome": true,
       "chromeos_is_browser_only": true,
       "dcheck_always_on": true,
       "is_component_build": false,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 1cd2daaa..82d4ba6d 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -43073,7 +43073,6 @@
   <int value="-632030508" label="NativeWindowNavButtons:disabled"/>
   <int value="-631740127" label="inert-visual-viewport"/>
   <int value="-631614101" label="CameraSystemWebApp:enabled"/>
-  <int value="-630946893" label="TabSearchFixedEntrypoint:enabled"/>
   <int value="-629041881" label="MuteNotificationsDuringScreenShare:disabled"/>
   <int value="-626329144" label="SyncSupportTrustedVaultPassphrase:enabled"/>
   <int value="-626211146" label="DesktopMinimalUI:disabled"/>
@@ -44555,7 +44554,6 @@
   <int value="879699575" label="disable-gesture-tap-highlight"/>
   <int value="879992337" label="disable-pull-to-refresh-effect"/>
   <int value="880510010" label="enable-permissions-bubbles"/>
-  <int value="880677998" label="TabSearchFixedEntrypoint:disabled"/>
   <int value="883190338" label="PrintWithReducedRasterization:disabled"/>
   <int value="884106779" label="supervised-user-safesites"/>
   <int value="885004540" label="ArcEnableApplicationZoomFeature:enabled"/>
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
index 7e8db6b..4957dbcc 100644
--- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -9293,7 +9293,17 @@
       label="The activity is ready to be drawn, although likely empty."/>
   <suffix name="FirstFragmentInflated"
       label="The first fragment is ready to be drawn, the first meaningful
-             paint."/>
+             paint. This version is buggy as it records the timestamp this
+             event happens since the system was booted, which is not extended
+             to measure. (http://crbug.com/1138660)">
+    <obsolete>
+      Deprecated and replaced with FirstFragmentInflatedV2 as of 10/2020.
+    </obsolete>
+  </suffix>
+  <suffix name="FirstFragmentInflatedV2"
+      label="The first fragment is ready to be drawn, the first meaningful
+             paint. Version V2 fixed an issue that previous data was not
+             recording the time duration from FRE launched."/>
   <suffix name="FreCompleted" label="Entire FRE is completed."/>
   <suffix name="TosAccepted" label="ToS is accepted."/>
   <suffix name="TriggerLayoutInflation"
@@ -11898,6 +11908,7 @@
   <suffix name="Network" label=""/>
   <suffix name="Network-selection" label=""/>
   <suffix name="Packaged-license" label=""/>
+  <suffix name="Parental-handoff" label=""/>
   <suffix name="Recommend-apps" label=""/>
   <suffix name="Reset" label=""/>
   <suffix name="Supervision-transition" label=""/>
@@ -11952,6 +11963,7 @@
   <suffix name="Oauth-enrollment.Completed" label=""/>
   <suffix name="Packaged-license.DontEnroll" label=""/>
   <suffix name="Packaged-license.Enroll" label=""/>
+  <suffix name="Parental-Handoff.Done" label=""/>
   <suffix name="Recommend-apps.Selected" label=""/>
   <suffix name="Recommend-apps.Skipped" label=""/>
   <suffix name="Reset.Cancel" label=""/>
diff --git a/tools/metrics/histograms/histograms_xml/net/histograms.xml b/tools/metrics/histograms/histograms_xml/net/histograms.xml
index 9417565..53ed646 100644
--- a/tools/metrics/histograms/histograms_xml/net/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/net/histograms.xml
@@ -2996,6 +2996,16 @@
   </summary>
 </histogram>
 
+<histogram name="Net.QuicSession.MigrateToSocketSuccess" enum="Boolean"
+    expires_after="2021-05-11">
+  <owner>renjietang@chromium.org</owner>
+  <owner>src/net/quic/OWNERS</owner>
+  <summary>
+    Records whether the migration of the QuicSession to a new socket is
+    successful.
+  </summary>
+</histogram>
+
 <histogram name="Net.QuicSession.MinRTT" units="ms" expires_after="2021-05-11">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
@@ -3024,6 +3034,13 @@
   </summary>
 </histogram>
 
+<histogram name="Net.QuicSession.NumMigrations" units="units"
+    expires_after="2021-05-11">
+  <owner>renjietang@chromium.org</owner>
+  <owner>src/net/quic/OWNERS</owner>
+  <summary>The number of successful migrations for a QUIC session.</summary>
+</histogram>
+
 <histogram name="Net.QuicSession.NumMigrationsExercisedBeforePublicReset"
     units="migrations" expires_after="2021-05-11">
   <owner>zhongyi@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/optimization/histograms.xml b/tools/metrics/histograms/histograms_xml/optimization/histograms.xml
index c65e1f86..145628d 100644
--- a/tools/metrics/histograms/histograms_xml/optimization/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/optimization/histograms.xml
@@ -55,7 +55,7 @@
 </histogram>
 
 <histogram name="OptimizationGuide.ClearHostModelFeatures.StoreAvailable"
-    units="BooleanAvailable" expires_after="2020-11-30">
+    units="BooleanAvailable" expires_after="2021-03-31">
   <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
@@ -65,9 +65,9 @@
 </histogram>
 
 <histogram name="OptimizationGuide.HintCache.HintType.Loaded"
-    enum="HintCacheStoreEntryType" expires_after="2020-11-30">
+    enum="HintCacheStoreEntryType" expires_after="2021-03-31">
   <owner>mcrouse@chromium.org</owner>
-  <owner>dougarnett@chromium.org</owner>
+  <owner>sophiechang@chromium.org</owner>
   <summary>
     Records the store entry type of a hint when it is loaded from the hint cache
     store.
@@ -76,8 +76,8 @@
 
 <histogram name="OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult"
     enum="OptimizationGuideHintCacheLevelDBStoreLoadMetadataResult"
-    expires_after="2020-11-30">
-  <owner>dougarnett@chromium.org</owner>
+    expires_after="2021-03-31">
+  <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
     Records the result of loading the metadata while initializing the
@@ -88,7 +88,7 @@
 <histogram name="OptimizationGuide.HintCacheLevelDBStore.Status"
     enum="OptimizationGuideHintCacheLevelDBStoreStatus"
     expires_after="2021-04-18">
-  <owner>dougarnett@chromium.org</owner>
+  <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
     Records each status change within the HintCacheLevelDBStore.
@@ -97,7 +97,7 @@
 
 <histogram base="true"
     name="OptimizationGuide.HintsFetcher.GetHintsRequest.ActiveRequestCanceled"
-    units="counts" expires_after="2020-11-30">
+    units="counts" expires_after="2021-03-31">
   <owner>sophiechang@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -129,7 +129,7 @@
 <histogram name="OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount"
     units="total host count" expires_after="2021-03-15">
   <owner>mcrouse@chromium.org</owner>
-  <owner>dougarnett@chromium.org</owner>
+  <owner>sophiechang@chromium.org</owner>
   <summary>
     Records the number of hosts selected for sending a hint request. This will
     be captured when any hint request is initiated.
@@ -139,7 +139,7 @@
 <histogram name="OptimizationGuide.HintsFetcher.GetHintsRequest.NetErrorCode"
     enum="NetErrorCodes" expires_after="2021-04-04">
   <owner>mcrouse@chromium.org</owner>
-  <owner>dougarnett@chromium.org</owner>
+  <owner>sophiechang@chromium.org</owner>
   <summary>
     Net error codes for HintsFetch requests to the Optimization Guide Service on
     success and failure.
@@ -149,7 +149,7 @@
 <histogram name="OptimizationGuide.HintsFetcher.GetHintsRequest.Status"
     enum="HttpResponseCode" expires_after="2021-04-04">
   <owner>mcrouse@chromium.org</owner>
-  <owner>dougarnett@chromium.org</owner>
+  <owner>sophiechang@chromium.org</owner>
   <summary>
     For each HintsFetch request to the Optimization Guide Service, log the HTTP
     response code on success and failure.
@@ -170,7 +170,7 @@
     enum="OptimizationGuideHintsFetcherRequestStatus"
     expires_after="2021-04-04">
   <owner>mcrouse@chromium.org</owner>
-  <owner>dougarnett@chromium.org</owner>
+  <owner>sophiechang@chromium.org</owner>
   <summary>
     The status of making a Batch Update context request of the OptmizationGuide
     HintsFetcher. This includes whether a network request was actually sent or
@@ -182,7 +182,7 @@
     enum="OptimizationGuideHintsFetcherRequestStatus"
     expires_after="2021-04-04">
   <owner>mcrouse@chromium.org</owner>
-  <owner>dougarnett@chromium.org</owner>
+  <owner>sophiechang@chromium.org</owner>
   <summary>
     The status of making a Page Navigation context request of the
     OptmizationGuide HintsFetcher. This includes whether a network request was
@@ -192,9 +192,9 @@
 
 <histogram
     name="OptimizationGuide.HintsFetcher.TopHostProvider.BlacklistSize.OnInitialize"
-    units="total host count" expires_after="2020-11-30">
+    units="total host count" expires_after="2021-03-31">
   <owner>mcrouse@chromium.org</owner>
-  <owner>dougarnett@chromium.org</owner>
+  <owner>sophiechang@chromium.org</owner>
   <summary>
     Records the number of hosts placed on the HintsFetcherTopHostBlacklist when
     it is initialized.
@@ -203,9 +203,9 @@
 
 <histogram
     name="OptimizationGuide.HintsFetcher.TopHostProvider.BlacklistSize.OnRequest"
-    units="total host count" expires_after="2020-11-30">
+    units="total host count" expires_after="2021-03-31">
   <owner>mcrouse@chromium.org</owner>
-  <owner>dougarnett@chromium.org</owner>
+  <owner>sophiechang@chromium.org</owner>
   <summary>
     Records the number of hosts on the HintsFetcherTopHostBlacklist when top
     hosts are requested.
@@ -214,7 +214,7 @@
 
 <histogram
     name="OptimizationGuide.HintsManager.ConcurrentPageNavigationFetches"
-    units="counts" expires_after="2020-11-30">
+    units="counts" expires_after="2021-03-31">
   <owner>sophiechang@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -238,7 +238,7 @@
 </histogram>
 
 <histogram name="OptimizationGuide.IsPredictionModelValid" units="BooleanValid"
-    expires_after="2020-11-30">
+    expires_after="2021-03-31">
   <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
@@ -250,7 +250,7 @@
 
 <histogram base="true" name="OptimizationGuide.OptimizationFilterStatus"
     enum="OptimizationGuideOptimizationFilterStatus" expires_after="2021-04-04">
-  <owner>dougarnett@chromium.org</owner>
+  <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
     Status of processing OptimizationFilter configurations for server-provided
@@ -260,7 +260,7 @@
 </histogram>
 
 <histogram name="OptimizationGuide.OptimizationHintsComponent.MajorVersion"
-    units="major version number" expires_after="2020-11-30">
+    units="major version number" expires_after="2021-03-31">
   <owner>sophiechang@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -282,7 +282,7 @@
 </histogram>
 
 <histogram name="OptimizationGuide.PredictionManager.HostModelFeaturesMapSize"
-    units="total host count" expires_after="2020-11-30">
+    units="total host count" expires_after="2021-03-31">
   <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
@@ -307,7 +307,7 @@
 
 <histogram
     name="OptimizationGuide.PredictionModelFetcher.GetModelsRequest.HostCount"
-    units="total host count" expires_after="2021-01-31">
+    units="total host count" expires_after="2021-03-31">
   <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
@@ -319,7 +319,7 @@
 
 <histogram
     name="OptimizationGuide.PredictionModelFetcher.GetModelsResponse.HostModelFeatureCount"
-    units="units" expires_after="2020-11-30">
+    units="units" expires_after="2021-03-31">
   <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
@@ -330,7 +330,7 @@
 
 <histogram
     name="OptimizationGuide.PredictionModelFetcher.GetModelsResponse.NetErrorCode"
-    enum="NetErrorCodes" expires_after="2021-01-31">
+    enum="NetErrorCodes" expires_after="2021-03-31">
   <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
@@ -341,7 +341,7 @@
 
 <histogram
     name="OptimizationGuide.PredictionModelFetcher.GetModelsResponse.Status"
-    enum="HttpResponseCode" expires_after="2021-01-31">
+    enum="HttpResponseCode" expires_after="2021-03-31">
   <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
@@ -351,7 +351,7 @@
 </histogram>
 
 <histogram name="OptimizationGuide.PredictionModelLoadedVersion"
-    units="version number" expires_after="2020-11-30">
+    units="version number" expires_after="2021-03-31">
   <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
@@ -363,7 +363,7 @@
 
 <histogram
     name="OptimizationGuide.PredictionModelStore.HostModelFeaturesLoadMetadataResult"
-    enum="BooleanLoaded" expires_after="2020-11-30">
+    enum="BooleanLoaded" expires_after="2021-03-31">
   <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
@@ -373,7 +373,7 @@
 </histogram>
 
 <histogram name="OptimizationGuide.PredictionModelUpdateVersion"
-    units="version number" expires_after="2021-01-31">
+    units="version number" expires_after="2021-03-31">
   <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
@@ -383,7 +383,7 @@
 </histogram>
 
 <histogram name="OptimizationGuide.PredictionModelValidationLatency" units="ms"
-    expires_after="2021-01-31">
+    expires_after="2021-03-31">
   <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
@@ -396,7 +396,7 @@
 
 <histogram name="OptimizationGuide.ProcessHintsResult"
     enum="OptimizationGuideProcessHintsResult" expires_after="2021-04-04">
-  <owner>dougarnett@chromium.org</owner>
+  <owner>mcrouse@chromium.org</owner>
   <owner>sophiechang@chromium.org</owner>
   <summary>
     Whether processing the hints succeeded or failed at a particular step.
@@ -433,7 +433,7 @@
 
 <histogram base="true" name="OptimizationGuide.TargetDecision"
     enum="OptimizationGuideOptimizationTargetDecision"
-    expires_after="2021-01-31">
+    expires_after="2021-03-31">
   <owner>sophiechang@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml
index 52e44f53..f4dc48b 100644
--- a/tools/metrics/histograms/histograms_xml/others/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -1167,8 +1167,9 @@
 </histogram>
 
 <histogram name="BatteryStatus.StartAndroid" enum="BooleanSuccess"
-    expires_after="M85">
+    expires_after="M92">
   <owner>timvolodine@chromium.org</owner>
+  <owner>src/services/device/battery/OWNERS</owner>
   <summary>
     Whether the Battery Status API was successfully started up on Android.
   </summary>
@@ -10620,8 +10621,9 @@
 </histogram>
 
 <histogram name="Previews.OptOut.UserOptedOut" enum="PreviewsUserOptedOut"
-    expires_after="2020-01-31">
+    expires_after="2021-03-31">
   <owner>sophiechang@chromium.org</owner>
+  <owner>mcrouse@chromium.org</owner>
   <summary>
     Whether the user chose to reload the original page when shown a preview.
   </summary>
diff --git a/ui/chromeos/file_manager_strings.grdp b/ui/chromeos/file_manager_strings.grdp
index 0334e6f0d..69fa5a16 100644
--- a/ui/chromeos/file_manager_strings.grdp
+++ b/ui/chromeos/file_manager_strings.grdp
@@ -629,7 +629,7 @@
     Cancel selection
   </message>
   <message name="IDS_FILE_BROWSER_READ_ONLY_LABEL" desc="Label for an indicator which means that the current folder is read-only.">
-    Read only
+    Read-only
   </message>
   <message name="IDS_FILE_BROWSER_CHANGE_TO_LISTVIEW_BUTTON_LABEL" desc="Label for button that changes the view mode to 'list view' mode.">
     Switch to list view
@@ -1478,7 +1478,7 @@
     More...
   </message>
 <message name="IDS_FILE_BROWSER_READONLY_INDICATOR_TOOLTIP" desc="Tooltip for the readonly indicator in the Files app.">
-    Files in this folder are read only. Some activities are not supported.
+    The contents of this folder are read-only. Some activities are not supported.
   </message>
   <message name="IDS_FILE_BROWSER_SELECTION_MENU_BUTTON_TOOLTIP" desc="Tooltip for the button to open the context menu of currently selected items in the Files app.">
     More...
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_READONLY_INDICATOR_TOOLTIP.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_READONLY_INDICATOR_TOOLTIP.png.sha1
index 9f0a86a4..e7ffa56 100644
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_READONLY_INDICATOR_TOOLTIP.png.sha1
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_READONLY_INDICATOR_TOOLTIP.png.sha1
@@ -1 +1 @@
-302891a6bc0bfbefc241c4b81ff4dac751d56fa2
\ No newline at end of file
+dae3c304b7b5c663c69303fe9082f5d980fca41e
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_READ_ONLY_LABEL.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_READ_ONLY_LABEL.png.sha1
index a010d24..e7ffa56 100644
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_READ_ONLY_LABEL.png.sha1
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_READ_ONLY_LABEL.png.sha1
@@ -1 +1 @@
-3f24b79e981374576ae28191874fea6b7e43d896
\ No newline at end of file
+dae3c304b7b5c663c69303fe9082f5d980fca41e
diff --git a/ui/file_manager/file_manager/foreground/elements/files_tooltip.html b/ui/file_manager/file_manager/foreground/elements/files_tooltip.html
index 878e5fa..13c2e40 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_tooltip.html
+++ b/ui/file_manager/file_manager/foreground/elements/files_tooltip.html
@@ -65,6 +65,7 @@
         border-radius: 8px;
         box-shadow: 0 1px 2px 0 rgba(var(--google-grey-800-rgb), 30%),
             0 1px 3px 1px rgba(var(--google-grey-800-rgb), 15%);
+        height: auto;
         margin-top: 4px;
         padding: 12px 16px;
       }
diff --git a/ui/file_manager/integration_tests/file_manager/files_tooltip.js b/ui/file_manager/integration_tests/file_manager/files_tooltip.js
index 7d98df0..b66b374e 100644
--- a/ui/file_manager/integration_tests/file_manager/files_tooltip.js
+++ b/ui/file_manager/integration_tests/file_manager/files_tooltip.js
@@ -105,8 +105,8 @@
     label =
         await remoteCall.waitForElement(appId, [tooltipQueryVisible, '#label']);
     chrome.test.assertEq(
-        'Files in this folder are read only.' +
-            ' Some activities are not supported.',
+        'The contents of this folder are read-only.' +
+        ' Some activities are not supported.',
         label.text);
     chrome.test.assertEq('card-tooltip', tooltip.attributes['class']);
     chrome.test.assertEq('card-label', label.attributes['class']);
diff --git a/ui/gfx/mojom/gpu_fence_handle.mojom b/ui/gfx/mojom/gpu_fence_handle.mojom
index 5de3ac36..18c88148 100644
--- a/ui/gfx/mojom/gpu_fence_handle.mojom
+++ b/ui/gfx/mojom/gpu_fence_handle.mojom
@@ -5,11 +5,10 @@
 module gfx.mojom;
 
 // See ui/gfx/ipc/gpu_fence_handle.h
-// A null handle means there is no GPU fence for synchronization.
 struct GpuFenceHandle {
   [EnableIf=is_posix]
-  handle<platform>? native_fd;
+  handle<platform> native_fd;
 
   [EnableIf=is_win]
-  handle<platform>? native_handle;
+  handle<platform> native_handle;
 };
diff --git a/ui/views/accessible_pane_view_unittest.cc b/ui/views/accessible_pane_view_unittest.cc
index 7ca93164..3e06282 100644
--- a/ui/views/accessible_pane_view_unittest.cc
+++ b/ui/views/accessible_pane_view_unittest.cc
@@ -21,17 +21,14 @@
 
 using AccessiblePaneViewTest = ViewsTestBase;
 
-class TestBarView : public AccessiblePaneView, public ButtonListener {
+class TestBarView : public AccessiblePaneView {
  public:
   TestBarView();
   ~TestBarView() override;
 
-  void ButtonPressed(Button* sender, const ui::Event& event) override;
-  LabelButton* child_button() const { return child_button_.get(); }
-  LabelButton* second_child_button() const {
-    return second_child_button_.get();
-  }
-  LabelButton* third_child_button() const { return third_child_button_.get(); }
+  LabelButton* child_button() const { return child_button_; }
+  LabelButton* second_child_button() const { return second_child_button_; }
+  LabelButton* third_child_button() const { return third_child_button_; }
   LabelButton* not_child_button() const { return not_child_button_.get(); }
 
   View* GetDefaultFocusableChild() override;
@@ -39,9 +36,9 @@
  private:
   void Init();
 
-  std::unique_ptr<LabelButton> child_button_;
-  std::unique_ptr<LabelButton> second_child_button_;
-  std::unique_ptr<LabelButton> third_child_button_;
+  LabelButton* child_button_;
+  LabelButton* second_child_button_;
+  LabelButton* third_child_button_;
   std::unique_ptr<LabelButton> not_child_button_;
 
   DISALLOW_COPY_AND_ASSIGN(TestBarView);
@@ -54,22 +51,17 @@
 
 TestBarView::~TestBarView() = default;
 
-void TestBarView::ButtonPressed(Button* sender, const ui::Event& event) {}
-
 void TestBarView::Init() {
   SetLayoutManager(std::make_unique<FillLayout>());
   base::string16 label;
-  child_button_ = std::make_unique<LabelButton>(this, label);
-  AddChildView(child_button_.get());
-  second_child_button_ = std::make_unique<LabelButton>(this, label);
-  AddChildView(second_child_button_.get());
-  third_child_button_ = std::make_unique<LabelButton>(this, label);
-  AddChildView(third_child_button_.get());
-  not_child_button_ = std::make_unique<LabelButton>(this, label);
+  child_button_ = AddChildView(std::make_unique<LabelButton>());
+  second_child_button_ = AddChildView(std::make_unique<LabelButton>());
+  third_child_button_ = AddChildView(std::make_unique<LabelButton>());
+  not_child_button_ = std::make_unique<LabelButton>();
 }
 
 View* TestBarView::GetDefaultFocusableChild() {
-  return child_button_.get();
+  return child_button_;
 }
 
 TEST_F(AccessiblePaneViewTest, SimpleSetPaneFocus) {
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc
index 5cbcdb3..436fcd27 100644
--- a/ui/views/bubble/bubble_frame_view.cc
+++ b/ui/views/bubble/bubble_frame_view.cc
@@ -158,20 +158,6 @@
 }
 
 // static
-std::unique_ptr<Button> BubbleFrameView::CreateCloseButton(
-    ButtonListener* listener) {
-  auto close_button = CreateVectorImageButtonWithNativeTheme(
-      listener, vector_icons::kCloseRoundedIcon);
-  close_button->SetTooltipText(l10n_util::GetStringUTF16(IDS_APP_CLOSE));
-  close_button->SizeToPreferredSize();
-  close_button->SetFocusForPlatform();
-
-  InstallCircleHighlightPathGenerator(close_button.get());
-
-  return close_button;
-}
-
-// static
 std::unique_ptr<Button> BubbleFrameView::CreateMinimizeButton(
     Button::PressedCallback callback) {
   auto minimize_button = CreateVectorImageButtonWithNativeTheme(
@@ -186,21 +172,6 @@
   return minimize_button;
 }
 
-// static
-std::unique_ptr<Button> BubbleFrameView::CreateMinimizeButton(
-    ButtonListener* listener) {
-  auto minimize_button = CreateVectorImageButtonWithNativeTheme(
-      listener, kWindowControlMinimizeIcon);
-  minimize_button->SetTooltipText(
-      l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE));
-  minimize_button->SizeToPreferredSize();
-  minimize_button->SetFocusForPlatform();
-
-  InstallCircleHighlightPathGenerator(minimize_button.get());
-
-  return minimize_button;
-}
-
 gfx::Rect BubbleFrameView::GetBoundsForClientView() const {
   // When NonClientView asks for this, the size of the frame view has been set
   // (i.e. |this|), but not the client view bounds.
diff --git a/ui/views/bubble/bubble_frame_view.h b/ui/views/bubble/bubble_frame_view.h
index 436556db..5476134 100644
--- a/ui/views/bubble/bubble_frame_view.h
+++ b/ui/views/bubble/bubble_frame_view.h
@@ -47,12 +47,10 @@
   // Creates a close button used in the corner of the dialog.
   static std::unique_ptr<Button> CreateCloseButton(
       Button::PressedCallback callback);
-  static std::unique_ptr<Button> CreateCloseButton(ButtonListener* listener);
 
   // Creates a minimize button used in the corner of the dialog.
   static std::unique_ptr<Button> CreateMinimizeButton(
       Button::PressedCallback callback);
-  static std::unique_ptr<Button> CreateMinimizeButton(ButtonListener* listener);
 
   // NonClientFrameView:
   gfx::Rect GetBoundsForClientView() const override;
diff --git a/ui/views/controls/webview/webview.cc b/ui/views/controls/webview/webview.cc
index 9ad6b1b..7efced0 100644
--- a/ui/views/controls/webview/webview.cc
+++ b/ui/views/controls/webview/webview.cc
@@ -93,25 +93,12 @@
   UpdateCrashedOverlayView();
   if (wc_owner_.get() != replacement)
     wc_owner_.reset();
-  if (embed_fullscreen_widget_mode_enabled_) {
-    is_embedding_fullscreen_widget_ =
-        fullscreen_native_view_for_testing_ ||
-        (web_contents() && web_contents()->GetFullscreenRenderWidgetHostView());
-  } else {
-    DCHECK(!is_embedding_fullscreen_widget_);
-  }
   AttachWebContentsNativeView();
   NotifyAccessibilityWebContentsChanged();
 
   MaybeEnableAutoResize();
 }
 
-void WebView::SetEmbedFullscreenWidgetMode(bool enable) {
-  DCHECK(!web_contents())
-      << "Cannot change mode while a WebContents is attached.";
-  embed_fullscreen_widget_mode_enabled_ = enable;
-}
-
 content::BrowserContext* WebView::GetBrowserContext() {
   return browser_context_;
 }
@@ -175,13 +162,11 @@
   // Only WebContentses that are in fullscreen mode and being screen-captured
   // will engage the special layout/sizing behavior.
   gfx::Rect holder_bounds = GetContentsBounds();
-  if (!embed_fullscreen_widget_mode_enabled_ || !web_contents() ||
-      !web_contents()->IsBeingCaptured() ||
+  if (!web_contents() || !web_contents()->IsBeingCaptured() ||
       web_contents()->GetPreferredSize().IsEmpty() ||
-      !(is_embedding_fullscreen_widget_ ||
-        (web_contents()->GetDelegate() &&
-         web_contents()->GetDelegate()->IsFullscreenForTabOrPending(
-             web_contents())))) {
+      !(web_contents()->GetDelegate() &&
+        web_contents()->GetDelegate()->IsFullscreenForTabOrPending(
+            web_contents()))) {
     // Reset the native view size.
     holder_->SetNativeViewSize(gfx::Size());
     holder_->SetBoundsRect(holder_bounds);
@@ -302,11 +287,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // WebView, content::WebContentsDelegate implementation:
 
-bool WebView::EmbedsFullscreenWidget() {
-  DCHECK(wc_owner_.get());
-  return embed_fullscreen_widget_mode_enabled_;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // WebView, content::WebContentsObserver implementation:
 
@@ -337,20 +317,8 @@
   NotifyAccessibilityWebContentsChanged();
 }
 
-void WebView::DidShowFullscreenWidget() {
-  if (embed_fullscreen_widget_mode_enabled_)
-    ReattachForFullscreenChange(true);
-}
-
-void WebView::DidDestroyFullscreenWidget() {
-  if (embed_fullscreen_widget_mode_enabled_)
-    ReattachForFullscreenChange(false);
-}
-
 void WebView::DidToggleFullscreenModeForTab(bool entered_fullscreen,
                                             bool will_cause_resize) {
-  if (embed_fullscreen_widget_mode_enabled_)
-    ReattachForFullscreenChange(entered_fullscreen);
 }
 
 void WebView::OnWebContentsFocused(
@@ -385,26 +353,12 @@
   if (!GetWidget() || !web_contents())
     return;
 
-  gfx::NativeView view_to_attach;
-  if (is_embedding_fullscreen_widget_) {
-    view_to_attach = fullscreen_native_view_for_testing_
-                         ? fullscreen_native_view_for_testing_
-                         : web_contents()
-                               ->GetFullscreenRenderWidgetHostView()
-                               ->GetNativeView();
-  } else {
-    view_to_attach = web_contents()->GetNativeView();
-  }
+  gfx::NativeView view_to_attach = web_contents()->GetNativeView();
   OnBoundsChanged(bounds());
   if (holder_->native_view() == view_to_attach)
     return;
 
   holder_->Attach(view_to_attach);
-  // Attach() asynchronously sets the bounds of the widget. Pepper expects
-  // fullscreen widgets to be sized immediately, so force a layout now.
-  // See https://crbug.com/361408 and https://crbug.com/id=959118.
-  if (is_embedding_fullscreen_widget_)
-    holder_->Layout();
 
   // We set the parent accessible of the native view to be our parent.
   UpdateNativeViewHostAccessibleParent(holder(), parent());
@@ -423,26 +377,6 @@
     holder_->Detach();
 }
 
-void WebView::ReattachForFullscreenChange(bool enter_fullscreen) {
-  DCHECK(embed_fullscreen_widget_mode_enabled_);
-  const bool web_contents_has_separate_fs_widget =
-      fullscreen_native_view_for_testing_ ||
-      (web_contents() && web_contents()->GetFullscreenRenderWidgetHostView());
-  if (is_embedding_fullscreen_widget_ || web_contents_has_separate_fs_widget) {
-    // Shutting down or starting up the embedding of the separate fullscreen
-    // widget.  Need to detach and re-attach to a different native view.
-    DetachWebContentsNativeView();
-    is_embedding_fullscreen_widget_ =
-        enter_fullscreen && web_contents_has_separate_fs_widget;
-    AttachWebContentsNativeView();
-  } else {
-    // Entering or exiting "non-Flash" fullscreen mode, where the native view is
-    // the same.  So, do not change attachment.
-    OnBoundsChanged(bounds());
-  }
-  NotifyAccessibilityWebContentsChanged();
-}
-
 void WebView::UpdateCrashedOverlayView() {
   if (web_contents() && web_contents()->IsCrashed() && crashed_overlay_view_) {
     SetFocusBehavior(FocusBehavior::NEVER);
diff --git a/ui/views/controls/webview/webview.h b/ui/views/controls/webview/webview.h
index f18eea14..1d4d5cd 100644
--- a/ui/views/controls/webview/webview.h
+++ b/ui/views/controls/webview/webview.h
@@ -54,12 +54,6 @@
   // those it implicitly creates via GetWebContents() above.
   void SetWebContents(content::WebContents* web_contents);
 
-  // If |mode| is true, WebView will register itself with WebContents as a
-  // WebContentsObserver, monitor for the showing/destruction of fullscreen
-  // render widgets, and alter its child view hierarchy to embed the fullscreen
-  // widget or restore the normal WebContentsView.
-  void SetEmbedFullscreenWidgetMode(bool mode);
-
   content::BrowserContext* GetBrowserContext();
   void SetBrowserContext(content::BrowserContext* browser_context);
 
@@ -142,9 +136,6 @@
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
   gfx::NativeViewAccessible GetNativeViewAccessible() override;
 
-  // Overridden from content::WebContentsDelegate:
-  bool EmbedsFullscreenWidget() override;
-
   // Overridden from content::WebContentsObserver:
   void RenderViewCreated(content::RenderViewHost* render_view_host) override;
   void RenderViewReady() override;
@@ -152,8 +143,6 @@
   void RenderViewHostChanged(content::RenderViewHost* old_host,
                              content::RenderViewHost* new_host) override;
   void WebContentsDestroyed() override;
-  void DidShowFullscreenWidget() override;
-  void DidDestroyFullscreenWidget() override;
   void DidToggleFullscreenModeForTab(bool entered_fullscreen,
                                      bool will_cause_resize) override;
   // Workaround for MSVC++ linker bug/feature that requires
@@ -174,7 +163,6 @@
 
   void AttachWebContentsNativeView();
   void DetachWebContentsNativeView();
-  void ReattachForFullscreenChange(bool enter_fullscreen);
   void UpdateCrashedOverlayView();
   void NotifyAccessibilityWebContentsChanged();
 
@@ -192,12 +180,6 @@
       AddChildView(std::make_unique<NativeViewHost>());
   // Non-NULL if |web_contents()| was created and is owned by this WebView.
   std::unique_ptr<content::WebContents> wc_owner_;
-  // When true, WebView auto-embeds fullscreen widgets as a child view.
-  bool embed_fullscreen_widget_mode_enabled_ = false;
-  // Set to true while WebView is embedding a fullscreen widget view as a child
-  // view instead of the normal WebContentsView render view. Note: This will be
-  // false in the case of non-Flash fullscreen.
-  bool is_embedding_fullscreen_widget_ = false;
   // Set to true when |holder_| is letterboxed (scaled to be smaller than this
   // view, to preserve its aspect ratio).
   bool is_letterboxing_ = false;
@@ -215,13 +197,6 @@
   // WebContents's main RenderFrameHost.
   ui::AXTreeID child_ax_tree_id_;
 
-  // Used as the fullscreen NativeView if
-  // |embed_fullscreen_widget_mode_enabled_| is enabled. This is only set in
-  // tests as injecting a different value for
-  // WebContents::GetFullscreenRenderWidgetHostView() is rather tricky in
-  // unit-tests.
-  gfx::NativeView fullscreen_native_view_for_testing_ = nullptr;
-
   DISALLOW_COPY_AND_ASSIGN(WebView);
 };
 
diff --git a/ui/views/controls/webview/webview_unittest.cc b/ui/views/controls/webview/webview_unittest.cc
index a6bad73..cca541a 100644
--- a/ui/views/controls/webview/webview_unittest.cc
+++ b/ui/views/controls/webview/webview_unittest.cc
@@ -191,10 +191,6 @@
         content::WebContents::CreateParams(browser_context_.get()));
   }
 
-  void SetFullscreenNativeView(WebView* web_view, gfx::NativeView native_view) {
-    web_view->fullscreen_native_view_for_testing_ = native_view;
-  }
-
  private:
   std::unique_ptr<content::RenderViewHostTestEnabler> rvh_enabler_;
   std::unique_ptr<content::TestBrowserContext> browser_context_;
@@ -303,196 +299,6 @@
   parent2->Close();
 }
 
-// Tests that the layout of the NativeViewHost within WebView behaves as
-// expected when embedding a fullscreen widget during WebContents screen
-// capture.
-TEST_F(WebViewUnitTest, EmbeddedFullscreenDuringScreenCapture_Layout) {
-  web_view()->SetEmbedFullscreenWidgetMode(true);
-  ASSERT_EQ(1u, web_view()->children().size());
-
-  const std::unique_ptr<content::WebContents> web_contents(CreateWebContents());
-  WebViewTestWebContentsDelegate delegate;
-  web_contents->SetDelegate(&delegate);
-  web_view()->SetWebContents(web_contents.get());
-
-  // Initially, the holder should fill the entire WebView.
-  EXPECT_EQ(gfx::Rect(0, 0, 100, 100), holder()->bounds());
-
-  // Simulate a transition into fullscreen mode, but without screen capture
-  // active on the WebContents, the holder should still fill the entire
-  // WebView like before.
-  delegate.set_is_fullscreened(true);
-  static_cast<content::WebContentsObserver*>(web_view())
-      ->DidToggleFullscreenModeForTab(true, false);
-  EXPECT_EQ(gfx::Rect(0, 0, 100, 100), holder()->bounds());
-
-  // ...and transition back out of fullscreen mode.
-  delegate.set_is_fullscreened(false);
-  static_cast<content::WebContentsObserver*>(web_view())
-      ->DidToggleFullscreenModeForTab(false, false);
-  EXPECT_EQ(gfx::Rect(0, 0, 100, 100), holder()->bounds());
-
-  // Now, begin screen capture of the WebContents and then enter fullscreen
-  // mode.  This time, the holder should be centered within WebView and
-  // sized to match the capture size.
-  const gfx::Size capture_size(64, 48);
-  web_contents->IncrementCapturerCount(capture_size, /* stay_hidden */ false);
-  delegate.set_is_fullscreened(true);
-  static_cast<content::WebContentsObserver*>(web_view())
-      ->DidToggleFullscreenModeForTab(true, false);
-
-  // The expected size should be scaled to whichever dimension matches the
-  // holder first, with the other scaled from the capture size to match the
-  // holder.  So 100, 100 holder size and 64, 48 capture size gives:
-  // 100 / 64 * 48 = 75
-  // The positioning centers the unmatched holder/capture dimension, giving:
-  // (100 - 75 = 25) / 2 = 12
-  EXPECT_EQ(gfx::Rect(0, 12, 100, 75), holder()->bounds());
-
-  // Resize the WebView so that its width is smaller than the capture width.
-  // Expect the holder to be scaled-down, letterboxed style.
-  web_view()->SetBoundsRect(gfx::Rect(0, 0, 32, 100));
-  EXPECT_EQ(gfx::Rect(0, 38, 32, 24), holder()->bounds());
-
-  // Resize the WebView so that its height is smaller than the capture height.
-  // Expect the holder to be scaled-down, pillarboxed style.
-  web_view()->SetBoundsRect(gfx::Rect(0, 0, 100, 24));
-  EXPECT_EQ(gfx::Rect(34, 0, 32, 24), holder()->bounds());
-
-  // Transition back out of fullscreen mode a final time and confirm the bounds
-  // of the holder fill the entire WebView once again.
-  delegate.set_is_fullscreened(false);
-  static_cast<content::WebContentsObserver*>(web_view())
-      ->DidToggleFullscreenModeForTab(false, false);
-  EXPECT_EQ(gfx::Rect(0, 0, 100, 24), holder()->bounds());
-}
-
-// Tests that a WebView correctly switches between WebContentses when one of
-// them is embedding a fullscreen widget during WebContents screen capture.
-TEST_F(WebViewUnitTest, EmbeddedFullscreenDuringScreenCapture_Switching) {
-  web_view()->SetEmbedFullscreenWidgetMode(true);
-  ASSERT_EQ(1u, web_view()->children().size());
-  const gfx::NativeView unset_native_view = holder()->native_view();
-
-  // Create two WebContentses to switch between.
-  const std::unique_ptr<content::WebContents> web_contents1(
-      CreateWebContents());
-  WebViewTestWebContentsDelegate delegate1;
-  web_contents1->SetDelegate(&delegate1);
-  const std::unique_ptr<content::WebContents> web_contents2(
-      CreateWebContents());
-  WebViewTestWebContentsDelegate delegate2;
-  web_contents2->SetDelegate(&delegate2);
-
-  EXPECT_NE(web_contents1->GetNativeView(), holder()->native_view());
-  web_view()->SetWebContents(web_contents1.get());
-  EXPECT_EQ(web_contents1->GetNativeView(), holder()->native_view());
-  EXPECT_EQ(gfx::Rect(0, 0, 100, 100), holder()->bounds());
-
-  // Begin screen capture of the WebContents and then enter fullscreen mode.
-  // The native view should not have changed, but the layout of its holder will
-  // have (indicates WebView has responded).
-  const gfx::Size capture_size(64, 48);
-  web_contents1->IncrementCapturerCount(capture_size, /* stay_hidden */ false);
-  delegate1.set_is_fullscreened(true);
-  static_cast<content::WebContentsObserver*>(web_view())
-      ->DidToggleFullscreenModeForTab(true, false);
-  EXPECT_EQ(web_contents1->GetNativeView(), holder()->native_view());
-  EXPECT_EQ(gfx::Rect(0, 12, 100, 75), holder()->bounds());
-
-  // When setting the WebContents to nullptr, the native view should become
-  // unset.
-  web_view()->SetWebContents(nullptr);
-  EXPECT_EQ(unset_native_view, holder()->native_view());
-
-  // ...and when setting the WebContents back to the currently-fullscreened
-  // instance, expect the native view and layout to reflect that.
-  web_view()->SetWebContents(web_contents1.get());
-  EXPECT_EQ(web_contents1->GetNativeView(), holder()->native_view());
-  EXPECT_EQ(gfx::Rect(0, 12, 100, 75), holder()->bounds());
-
-  // Now, switch to a different, non-null WebContents instance and check that
-  // the native view has changed and the holder is filling WebView again.
-  web_view()->SetWebContents(web_contents2.get());
-  EXPECT_EQ(web_contents2->GetNativeView(), holder()->native_view());
-  EXPECT_EQ(gfx::Rect(0, 0, 100, 100), holder()->bounds());
-
-  // Finally, switch back to the first WebContents (still fullscreened).
-  web_view()->SetWebContents(web_contents1.get());
-  EXPECT_EQ(web_contents1->GetNativeView(), holder()->native_view());
-  EXPECT_EQ(gfx::Rect(0, 12, 100, 75), holder()->bounds());
-}
-
-// Tests that clicking anywhere within the bounds of WebView, and either outside
-// or inside the bounds of its child NativeViewHost, causes WebView to gain
-// focus.
-TEST_F(WebViewUnitTest, EmbeddedFullscreenDuringScreenCapture_ClickToFocus) {
-  // For this test, add another View that can take focus away from WebView.
-  web_view()->SetBoundsRect(gfx::Rect(0, 0, 100, 90));
-  views::View* const something_to_focus = new views::View();
-  something_to_focus->SetBoundsRect(gfx::Rect(0, 90, 100, 10));
-  something_to_focus->SetFocusBehavior(View::FocusBehavior::ALWAYS);
-  top_level_widget()->GetContentsView()->AddChildView(something_to_focus);
-
-  web_view()->SetEmbedFullscreenWidgetMode(true);
-  ASSERT_EQ(1u, web_view()->children().size());
-
-  const std::unique_ptr<content::WebContents> web_contents(CreateWebContents());
-  WebViewTestWebContentsDelegate delegate;
-  web_contents->SetDelegate(&delegate);
-  web_view()->SetWebContents(web_contents.get());
-
-  // Begin screen capture of the WebContents and then enter fullscreen mode.
-  // The holder should be centered within WebView and sized to match the capture
-  // size.
-  const gfx::Size capture_size(64, 48);
-  web_contents->IncrementCapturerCount(capture_size, /* stay_hidden */ false);
-  delegate.set_is_fullscreened(true);
-  static_cast<content::WebContentsObserver*>(web_view())
-      ->DidToggleFullscreenModeForTab(true, false);
-  EXPECT_EQ(gfx::Rect(0, 7, 100, 75), holder()->bounds());
-
-  // Focus the other widget.
-  something_to_focus->RequestFocus();
-  EXPECT_FALSE(web_view()->HasFocus());
-  EXPECT_FALSE(holder()->HasFocus());
-  EXPECT_TRUE(something_to_focus->HasFocus());
-
-  // Send mouse press event to WebView outside the bounds of the holder, and
-  // confirm WebView took focus.
-  const ui::MouseEvent click_outside_holder(
-      ui::ET_MOUSE_PRESSED, gfx::Point(1, 1),
-      gfx::Point(),  // Immaterial.
-      ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
-  EXPECT_TRUE(static_cast<views::View*>(web_view())
-                  ->OnMousePressed(click_outside_holder));
-  EXPECT_TRUE(web_view()->HasFocus());
-  EXPECT_FALSE(holder()->HasFocus());
-  EXPECT_FALSE(something_to_focus->HasFocus());
-
-  // Focus the other widget again.
-  something_to_focus->RequestFocus();
-  EXPECT_FALSE(web_view()->HasFocus());
-  EXPECT_FALSE(holder()->HasFocus());
-  EXPECT_TRUE(something_to_focus->HasFocus());
-
-  // Send a mouse press event within the bounds of the holder and expect no
-  // focus change.  The reason is that WebView is not supposed to handle mouse
-  // events within the bounds of the holder, and it would be up to the
-  // WebContents native view to grab the focus instead.  In this test
-  // environment, the WebContents native view doesn't include the implementation
-  // needed to grab focus, so no focus change will occur.
-  const ui::MouseEvent click_inside_holder(
-      ui::ET_MOUSE_PRESSED, web_view()->bounds().CenterPoint(),
-      gfx::Point(),  // Immaterial.
-      ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
-  EXPECT_FALSE(static_cast<views::View*>(web_view())
-                   ->OnMousePressed(click_inside_holder));
-  EXPECT_FALSE(web_view()->HasFocus());
-  EXPECT_FALSE(holder()->HasFocus());
-  EXPECT_TRUE(something_to_focus->HasFocus());
-}
-
 // Verifies that there is no crash in WebView destructor
 // if WebView is already removed from Widget.
 TEST_F(WebViewUnitTest, DetachedWebViewDestructor) {
@@ -585,44 +391,4 @@
   EXPECT_EQ(browser_context.get(), web_contents->GetBrowserContext());
 }
 
-#if defined(USE_AURA)
-namespace {
-
-// TODO(sky): factor this for mac.
-gfx::Rect GetNativeViewBounds(gfx::NativeView native_view) {
-  return native_view->bounds();
-}
-
-}  // namespace
-
-TEST_F(WebViewUnitTest, LayoutFullscreenNativeView) {
-  web_view()->SetEmbedFullscreenWidgetMode(true);
-  // WebView lazily creates WebContents. Force creation.
-  web_view()->GetWebContents();
-  // Layout is async, force a layout now to ensure bounds are set.
-  web_view()->Layout();
-  const gfx::Rect initial_bounds =
-      GetNativeViewBounds(web_view()->GetWebContents()->GetNativeView());
-  EXPECT_NE(gfx::Rect(), initial_bounds);
-
-  // Create another WebContents for a separate gfx::NativeView. The WebContent's
-  // gfx::NativeView is used as the fullscreen widget for web_view().
-  const std::unique_ptr<content::WebContents> fullscreen_web_contents(
-      CreateWebContents());
-  EXPECT_NE(initial_bounds,
-            GetNativeViewBounds(fullscreen_web_contents->GetNativeView()));
-  SetFullscreenNativeView(web_view(), fullscreen_web_contents->GetNativeView());
-
-  // Trigger going fullscreen. Once fullscreen, the fullscreen gfx::NativeView
-  // should be immediately resized.
-  static_cast<content::WebContentsObserver*>(web_view())
-      ->DidShowFullscreenWidget();
-  EXPECT_EQ(initial_bounds,
-            GetNativeViewBounds(fullscreen_web_contents->GetNativeView()));
-
-  static_cast<content::WebContentsObserver*>(web_view())
-      ->DidDestroyFullscreenWidget();
-}
-#endif
-
 }  // namespace views
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index bcf0235..efe18b5 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -3038,7 +3038,7 @@
         // we need to tell the RootView to send the mouse pressed event (which
         // sets capture, allowing subsequent WM_LBUTTONUP (note, _not_
         // WM_NCLBUTTONUP) to fire so that the appropriate WM_SYSCOMMAND can be
-        // sent by the applicable button's ButtonListener. We _have_ to do this
+        // sent by the applicable button's callback. We _have_ to do this this
         // way rather than letting Windows just send the syscommand itself (as
         // would happen if we never did this dance) because for some insane
         // reason DefWindowProc for WM_NCLBUTTONDOWN also renders the pressed
diff --git a/ui/views/window/frame_caption_button.cc b/ui/views/window/frame_caption_button.cc
index 4227b70..e8412e38 100644
--- a/ui/views/window/frame_caption_button.cc
+++ b/ui/views/window/frame_caption_button.cc
@@ -5,6 +5,7 @@
 #include "ui/views/window/frame_caption_button.h"
 
 #include <memory>
+#include <utility>
 
 #include "ui/base/hit_test.h"
 #include "ui/gfx/animation/slide_animation.h"
@@ -66,10 +67,10 @@
 // static
 const char FrameCaptionButton::kViewClassName[] = "FrameCaptionButton";
 
-FrameCaptionButton::FrameCaptionButton(views::ButtonListener* listener,
+FrameCaptionButton::FrameCaptionButton(PressedCallback callback,
                                        CaptionButtonIcon icon,
                                        int hit_test_type)
-    : Button(listener),
+    : Button(std::move(callback)),
       icon_(icon),
       background_color_(SK_ColorWHITE),
       paint_as_active_(false),
diff --git a/ui/views/window/frame_caption_button.h b/ui/views/window/frame_caption_button.h
index d04cc761..dd3733c 100644
--- a/ui/views/window/frame_caption_button.h
+++ b/ui/views/window/frame_caption_button.h
@@ -29,7 +29,7 @@
 
   static const char kViewClassName[];
 
-  FrameCaptionButton(views::ButtonListener* listener,
+  FrameCaptionButton(PressedCallback callback,
                      CaptionButtonIcon icon,
                      int hit_test_type);
   ~FrameCaptionButton() override;
diff --git a/ui/views/window/frame_caption_button_unittest.cc b/ui/views/window/frame_caption_button_unittest.cc
index d5c11b03..2c698f9 100644
--- a/ui/views/window/frame_caption_button_unittest.cc
+++ b/ui/views/window/frame_caption_button_unittest.cc
@@ -33,7 +33,8 @@
 }
 
 TEST(FrameCaptionButtonTest, DefaultAccessibilityFocus) {
-  FrameCaptionButton button(nullptr, CAPTION_BUTTON_ICON_MINIMIZE, HTMINBUTTON);
+  FrameCaptionButton button(Button::PressedCallback(),
+                            CAPTION_BUTTON_ICON_MINIMIZE, HTMINBUTTON);
   EXPECT_EQ(View::FocusBehavior::ACCESSIBLE_ONLY, button.GetFocusBehavior());
 }
 
diff --git a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
index 54b7dc44..d8194ba 100644
--- a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
+++ b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
@@ -145,9 +145,13 @@
         margin-top: 4px;
       }
     </style>
+    <!-- TODO(crbug/1139958): Remove "not chromeos" block when chromeVox issue is fixed-->
+    <!--Update both "not chromeos" and "chromeos" blocks if either changes-->
+<if expr="not chromeos">
     <dialog id="dialog" on-close="onNativeDialogClose_"
-        on-cancel="onNativeDialogCancel_" part="dialog" aria-labelledby="title">
-      <!-- This wrapper is necessary, such that the "pulse" animation is not
+        on-cancel="onNativeDialogCancel_" part="dialog"
+        aria-labelledby="title">
+    <!-- This wrapper is necessary, such that the "pulse" animation is not
         erroneously played when the user clicks on the outer-most scrollbar. -->
       <div id="content-wrapper" part="wrapper">
         <div class="top-container">
@@ -168,6 +172,32 @@
         <slot name="footer"></slot>
       </div>
     </dialog>
+</if>
+<if expr="chromeos">
+    <dialog id="dialog" on-close="onNativeDialogClose_"
+        on-cancel="onNativeDialogCancel_" part="dialog">
+    <!-- This wrapper is necessary, such that the "pulse" animation is not
+        erroneously played when the user clicks on the outer-most scrollbar. -->
+        <div id="content-wrapper" part="wrapper">
+          <div class="top-container">
+            <div id="title" class="title-container" tabindex="-1">
+              <slot name="title"></slot>
+            </div>
+            <cr-icon-button id="close" class="icon-clear"
+                hidden$="[[!showCloseButton]]" aria-label$="[[closeText]]"
+                on-click="cancel" on-keypress="onCloseKeypress_">
+            </cr-icon-button>
+          </div>
+          <slot name="header"></slot>
+          <div class="body-container" id="container" show-bottom-shadow
+              part="body-container">
+            <slot name="body"></slot>
+          </div>
+          <slot name="button-container"></slot>
+          <slot name="footer"></slot>
+        </div>
+    </dialog>
+</if>
   </template>
   <script src="cr_dialog.js"></script>
 </dom-module>
diff --git a/ui/webui/resources/cr_elements_resources.grdp b/ui/webui/resources/cr_elements_resources.grdp
index ded4e7e62..5577f2e74c 100644
--- a/ui/webui/resources/cr_elements_resources.grdp
+++ b/ui/webui/resources/cr_elements_resources.grdp
@@ -54,6 +54,7 @@
              type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_CR_DIALOG_HTML"
              file="cr_elements/cr_dialog/cr_dialog.html"
+             preprocess="true"
              type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_CR_DIALOG_JS"
              file="cr_elements/cr_dialog/cr_dialog.js"
diff --git a/ui/webui/resources/cr_elements_resources_v3.grdp b/ui/webui/resources/cr_elements_resources_v3.grdp
index 25b35ce..eac31b30 100644
--- a/ui/webui/resources/cr_elements_resources_v3.grdp
+++ b/ui/webui/resources/cr_elements_resources_v3.grdp
@@ -24,6 +24,7 @@
   <include name="IDR_CR_ELEMENTS_CR_DIALOG_M_JS"
          file="${root_gen_dir}/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.m.js"
          use_base_dir="false"
+         preprocess="true"
          type="BINDATA" />
   <include name="IDR_CR_ELEMENTS_CR_DRAWER_M_JS"
          file="${root_gen_dir}/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.m.js"
diff --git a/weblayer/browser/tab_impl.cc b/weblayer/browser/tab_impl.cc
index 59bba86..a05eb92 100644
--- a/weblayer/browser/tab_impl.cc
+++ b/weblayer/browser/tab_impl.cc
@@ -1007,10 +1007,6 @@
 #endif
 }
 
-bool TabImpl::EmbedsFullscreenWidget() {
-  return true;
-}
-
 void TabImpl::RequestMediaAccessPermission(
     content::WebContents* web_contents,
     const content::MediaStreamRequest& request,
diff --git a/weblayer/browser/tab_impl.h b/weblayer/browser/tab_impl.h
index e21928bc9..56c6d1c0 100644
--- a/weblayer/browser/tab_impl.h
+++ b/weblayer/browser/tab_impl.h
@@ -280,7 +280,6 @@
       content::WebContents* web_contents) override;
   bool OnlyExpandTopControlsAtPageTop() override;
   bool ShouldAnimateBrowserControlsHeightChanges() override;
-  bool EmbedsFullscreenWidget() override;
   void RequestMediaAccessPermission(
       content::WebContents* web_contents,
       const content::MediaStreamRequest& request,