diff --git a/DEPS b/DEPS
index 5832dbb..43331de 100644
--- a/DEPS
+++ b/DEPS
@@ -167,11 +167,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': '55f9cba6e2e7b8ff3ba4f1453349db26e547cb28',
+  'skia_revision': 'f22c57ddcc8c13712cbca4ed9bfc2f06dc8b895f',
   # 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': '517b740d3eeadd2df2cfbde1bdf4c406a68d0095',
+  'v8_revision': '9b58c027ceed56993c662e779b0e0a0803b76aa0',
   # 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.
@@ -230,7 +230,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': '8ea4f73b725e4846bcda63c9b02a2b11e1d53a77',
+  'catapult_revision': 'cc3b617bc9f8a91237c960023774a0c536ad8359',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -286,7 +286,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.
-  'spv_tools_revision': '2276e59788eaa6d7d8440602e5541acc304655b4',
+  'spv_tools_revision': '1b6fd37fa6f9c39be15d2e775948a6708afecb7c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -302,7 +302,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': 'd59fec5d706eb7ff403e83ae69ed999a3c13f6df',
+  'dawn_revision': '1093c4de2cfad715f0da1460aafbf88f47bd7bb1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -862,7 +862,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '9d77d68d79fa9e6b0b4e3a8d2e2cf4dbd86b718b',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'd3b93d4c73b8910c7ac72244f4ebc99fbed30671',
       'condition': 'checkout_linux',
   },
 
@@ -887,7 +887,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c6512213a7b74a8363c93788a9c376ebaeb4ec6c',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '61d3d4b0bd55ee9027a831d27210ddfcbb9531a7',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1280,7 +1280,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '407cb5ca3318449bc3c31b95b1767d4a0ffde5d1',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '8d061254d2f4272b4b40f9f8a4d3fd9307774acf',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1470,7 +1470,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '2701c130839edbeb226735b0775966b6423d9e83',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '8bbf9e2c6e40feb8efcbf276b43945a14d651e9b',
+    Var('webrtc_git') + '/src.git' + '@' + 'ac0a4cbbd85036c0c35ed4bc3383805ff00415dd',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1532,7 +1532,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d0b7b0ccae013cf1790ef46cc14b4ac4bfe1a0fe',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@b17e79b773ba081d830d0d282f11746042649364',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/network_service/aw_proxy_config_monitor.cc b/android_webview/browser/network_service/aw_proxy_config_monitor.cc
index f3e0190..25a3bf4 100644
--- a/android_webview/browser/network_service/aw_proxy_config_monitor.cc
+++ b/android_webview/browser/network_service/aw_proxy_config_monitor.cc
@@ -9,6 +9,7 @@
 
 #include "base/barrier_closure.h"
 #include "base/bind.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 
 namespace android_webview {
 
@@ -53,10 +54,10 @@
     network_context_params->initial_proxy_config =
         net::ProxyConfigWithAnnotation(proxy_config, NO_TRAFFIC_ANNOTATION_YET);
   } else {
-    network::mojom::ProxyConfigClientPtr proxy_config_client;
-    network_context_params->proxy_config_client_request =
-        mojo::MakeRequest(&proxy_config_client);
-    proxy_config_client_set_.AddPtr(std::move(proxy_config_client));
+    mojo::PendingRemote<network::mojom::ProxyConfigClient> proxy_config_client;
+    network_context_params->proxy_config_client_receiver =
+        proxy_config_client.InitWithNewPipeAndPassReceiver();
+    proxy_config_client_set_.Add(std::move(proxy_config_client));
 
     net::ProxyConfigWithAnnotation proxy_config;
     net::ProxyConfigService::ConfigAvailability availability =
@@ -69,22 +70,20 @@
 void AwProxyConfigMonitor::OnProxyConfigChanged(
     const net::ProxyConfigWithAnnotation& config,
     net::ProxyConfigService::ConfigAvailability availability) {
-  proxy_config_client_set_.ForAllPtrs(
-      [config,
-       availability](network::mojom::ProxyConfigClient* proxy_config_client) {
-        switch (availability) {
-          case net::ProxyConfigService::CONFIG_VALID:
-            proxy_config_client->OnProxyConfigUpdated(config);
-            break;
-          case net::ProxyConfigService::CONFIG_UNSET:
-            proxy_config_client->OnProxyConfigUpdated(
-                net::ProxyConfigWithAnnotation::CreateDirect());
-            break;
-          case net::ProxyConfigService::CONFIG_PENDING:
-            NOTREACHED();
-            break;
-        }
-      });
+  for (const auto& proxy_config_client : proxy_config_client_set_) {
+    switch (availability) {
+      case net::ProxyConfigService::CONFIG_VALID:
+        proxy_config_client->OnProxyConfigUpdated(config);
+        break;
+      case net::ProxyConfigService::CONFIG_UNSET:
+        proxy_config_client->OnProxyConfigUpdated(
+            net::ProxyConfigWithAnnotation::CreateDirect());
+        break;
+      case net::ProxyConfigService::CONFIG_PENDING:
+        NOTREACHED();
+        break;
+    }
+  }
 }
 
 std::string AwProxyConfigMonitor::SetProxyOverride(
@@ -105,18 +104,11 @@
 }
 
 void AwProxyConfigMonitor::FlushProxyConfig(base::OnceClosure callback) {
-  int count = 0;
-  proxy_config_client_set_.ForAllPtrs(
-      [&count](network::mojom::ProxyConfigClient* proxy_config_client) {
-        ++count;
-      });
-
+  int count = proxy_config_client_set_.size();
   base::RepeatingClosure closure =
       base::BarrierClosure(count, std::move(callback));
-  proxy_config_client_set_.ForAllPtrs(
-      [closure](network::mojom::ProxyConfigClient* proxy_config_client) {
-        proxy_config_client->FlushProxyConfig(closure);
-      });
+  for (auto& proxy_config_client : proxy_config_client_set_)
+    proxy_config_client->FlushProxyConfig(closure);
 }
 
 }  // namespace android_webview
diff --git a/android_webview/browser/network_service/aw_proxy_config_monitor.h b/android_webview/browser/network_service/aw_proxy_config_monitor.h
index 4e4fe7c..0be708b 100644
--- a/android_webview/browser/network_service/aw_proxy_config_monitor.h
+++ b/android_webview/browser/network_service/aw_proxy_config_monitor.h
@@ -9,7 +9,7 @@
 #include <string>
 #include <vector>
 
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
 #include "net/proxy_resolution/proxy_config_service_android.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 
@@ -47,8 +47,7 @@
   void FlushProxyConfig(base::OnceClosure callback);
 
   std::unique_ptr<net::ProxyConfigServiceAndroid> proxy_config_service_android_;
-  mojo::InterfacePtrSet<network::mojom::ProxyConfigClient>
-      proxy_config_client_set_;
+  mojo::RemoteSet<network::mojom::ProxyConfigClient> proxy_config_client_set_;
 };
 
 }  // namespace android_webview
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 65514ec..42c0c63 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1333,6 +1333,7 @@
     "//ash/strings",
     "//ash/wayland",
     "//components/discardable_memory/public/mojom",
+    "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
     "//services/device/public/cpp/bluetooth",
     "//services/device/public/mojom",
@@ -2033,6 +2034,7 @@
     "//device/bluetooth:mocks",
     "//extensions/common:common_constants",
     "//mojo/core/embedder",
+    "//mojo/public/cpp/bindings",
     "//net:net",
     "//services/device/public/cpp/bluetooth",
     "//services/media_session/public/cpp/test:test_support",
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index 0e4686f..fea4fe0 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -1313,7 +1313,7 @@
   ImeController* controller = Shell::Get()->ime_controller();
 
   TestImeControllerClient client;
-  controller->SetClient(client.CreateInterfacePtr());
+  controller->SetClient(client.CreateRemote());
   EXPECT_EQ(0, client.set_caps_lock_count_);
 
   // 1. Press Alt, Press Search, Release Search, Release Alt.
@@ -2370,7 +2370,7 @@
   ImeController* controller = Shell::Get()->ime_controller();
 
   TestImeControllerClient client;
-  controller->SetClient(client.CreateInterfacePtr());
+  controller->SetClient(client.CreateRemote());
 
   EXPECT_EQ(0, client.next_ime_count_);
 
diff --git a/ash/app_list/app_list_controller_impl_unittest.cc b/ash/app_list/app_list_controller_impl_unittest.cc
index a2a7bfa9..24dffcf2 100644
--- a/ash/app_list/app_list_controller_impl_unittest.cc
+++ b/ash/app_list/app_list_controller_impl_unittest.cc
@@ -208,7 +208,7 @@
   // Set IME client. Otherwise the emoji panel is unable to show.
   ImeController* ime_controller = Shell::Get()->ime_controller();
   TestImeControllerClient client;
-  ime_controller->SetClient(client.CreateInterfacePtr());
+  ime_controller->SetClient(client.CreateRemote());
 
   // Show the app list view and right-click on the search box with mouse. So the
   // text field's context menu shows.
diff --git a/ash/display/cros_display_config.cc b/ash/display/cros_display_config.cc
index 5dec98e..9328b25e 100644
--- a/ash/display/cros_display_config.cc
+++ b/ash/display/cros_display_config.cc
@@ -4,6 +4,8 @@
 
 #include "ash/display/cros_display_config.h"
 
+#include <utility>
+
 #include "ash/display/display_configuration_controller.h"
 #include "ash/display/display_prefs.h"
 #include "ash/display/overscan_calibrator.h"
@@ -17,6 +19,7 @@
 #include "base/bind.h"
 #include "base/optional.h"
 #include "base/strings/string_number_conversions.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
 #include "ui/display/display.h"
 #include "ui/display/display_layout.h"
 #include "ui/display/display_layout_builder.h"
@@ -480,16 +483,15 @@
 
 CrosDisplayConfig::~CrosDisplayConfig() {}
 
-void CrosDisplayConfig::BindRequest(
-    mojom::CrosDisplayConfigControllerRequest request) {
-  bindings_.AddBinding(this, std::move(request));
+void CrosDisplayConfig::BindReceiver(
+    mojo::PendingReceiver<mojom::CrosDisplayConfigController> receiver) {
+  receivers_.Add(this, std::move(receiver));
 }
 
 void CrosDisplayConfig::AddObserver(
-    mojom::CrosDisplayConfigObserverAssociatedPtrInfo observer) {
-  mojom::CrosDisplayConfigObserverAssociatedPtr observer_ptr;
-  observer_ptr.Bind(std::move(observer));
-  observers_.AddPtr(std::move(observer_ptr));
+    mojo::PendingAssociatedRemote<mojom::CrosDisplayConfigObserver> observer) {
+  observers_.Add(mojo::AssociatedRemote<mojom::CrosDisplayConfigObserver>(
+      std::move(observer)));
 }
 
 void CrosDisplayConfig::GetDisplayLayoutInfo(
@@ -888,9 +890,8 @@
 }
 
 void CrosDisplayConfig::NotifyObserversDisplayConfigChanged() {
-  observers_.ForAllPtrs([](mojom::CrosDisplayConfigObserver* observer) {
+  for (auto& observer : observers_)
     observer->OnDisplayConfigChanged();
-  });
 }
 
 OverscanCalibrator* CrosDisplayConfig::GetOverscanCalibrator(
diff --git a/ash/display/cros_display_config.h b/ash/display/cros_display_config.h
index 98ac39f..84fde52 100644
--- a/ash/display/cros_display_config.h
+++ b/ash/display/cros_display_config.h
@@ -12,8 +12,10 @@
 #include "ash/ash_export.h"
 #include "ash/public/mojom/cros_display_config.mojom.h"
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
 
 namespace ash {
 
@@ -26,11 +28,13 @@
   CrosDisplayConfig();
   ~CrosDisplayConfig() override;
 
-  void BindRequest(mojom::CrosDisplayConfigControllerRequest request);
+  void BindReceiver(
+      mojo::PendingReceiver<mojom::CrosDisplayConfigController> receiver);
 
   // mojom::CrosDisplayConfigController:
   void AddObserver(
-      mojom::CrosDisplayConfigObserverAssociatedPtrInfo observer) override;
+      mojo::PendingAssociatedRemote<mojom::CrosDisplayConfigObserver> observer)
+      override;
   void GetDisplayLayoutInfo(GetDisplayLayoutInfoCallback callback) override;
   void SetDisplayLayoutInfo(mojom::DisplayLayoutInfoPtr info,
                             SetDisplayLayoutInfoCallback callback) override;
@@ -60,8 +64,8 @@
   OverscanCalibrator* GetOverscanCalibrator(const std::string& id);
 
   std::unique_ptr<DisplayObserver> display_observer_;
-  mojo::BindingSet<mojom::CrosDisplayConfigController> bindings_;
-  mojo::AssociatedInterfacePtrSet<mojom::CrosDisplayConfigObserver> observers_;
+  mojo::ReceiverSet<mojom::CrosDisplayConfigController> receivers_;
+  mojo::AssociatedRemoteSet<mojom::CrosDisplayConfigObserver> observers_;
   std::map<std::string, std::unique_ptr<OverscanCalibrator>>
       overscan_calibrators_;
   std::unique_ptr<TouchCalibratorController> touch_calibrator_;
diff --git a/ash/display/cros_display_config_unittest.cc b/ash/display/cros_display_config_unittest.cc
index 204741e..4de84719 100644
--- a/ash/display/cros_display_config_unittest.cc
+++ b/ash/display/cros_display_config_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "ash/display/cros_display_config.h"
 
-#include "ash/display/cros_display_config.h"
 #include "ash/display/touch_calibrator_controller.h"
 #include "ash/public/mojom/cros_display_config.mojom.h"
 #include "ash/shell.h"
@@ -15,7 +14,8 @@
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/scoped_feature_list.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
 #include "ui/display/display_switches.h"
 #include "ui/display/manager/display_manager.h"
 #include "ui/display/manager/test/touch_transform_controller_test_api.h"
@@ -203,10 +203,11 @@
 
 TEST_F(CrosDisplayConfigTest, OnDisplayConfigChanged) {
   TestObserver observer;
-  mojom::CrosDisplayConfigObserverAssociatedPtr observer_ptr;
-  mojo::AssociatedBinding<mojom::CrosDisplayConfigObserver> binding(
-      &observer, mojo::MakeRequestAssociatedWithDedicatedPipe(&observer_ptr));
-  cros_display_config()->AddObserver(observer_ptr.PassInterface());
+  mojo::AssociatedRemote<mojom::CrosDisplayConfigObserver> observer_remote;
+  mojo::AssociatedReceiver<mojom::CrosDisplayConfigObserver> receiver(
+      &observer,
+      observer_remote.BindNewEndpointAndPassDedicatedReceiverForTesting());
+  cros_display_config()->AddObserver(observer_remote.Unbind());
   base::RunLoop().RunUntilIdle();
 
   // Adding one display should trigger one notification.
diff --git a/ash/ime/ime_controller.cc b/ash/ime/ime_controller.cc
index bb41780..cc6cd64 100644
--- a/ash/ime/ime_controller.cc
+++ b/ash/ime/ime_controller.cc
@@ -4,6 +4,8 @@
 
 #include "ash/ime/ime_controller.h"
 
+#include <utility>
+
 #include "ash/ime/ime_mode_indicator_view.h"
 #include "ash/ime/ime_switch_type.h"
 #include "ash/ime/mode_indicator_observer.h"
@@ -47,12 +49,14 @@
   observers_.RemoveObserver(observer);
 }
 
-void ImeController::BindRequest(mojom::ImeControllerRequest request) {
-  bindings_.AddBinding(this, std::move(request));
+void ImeController::BindReceiver(
+    mojo::PendingReceiver<mojom::ImeController> receiver) {
+  receivers_.Add(this, std::move(receiver));
 }
 
-void ImeController::SetClient(mojom::ImeControllerClientPtr client) {
-  client_ = std::move(client);
+void ImeController::SetClient(
+    mojo::PendingRemote<mojom::ImeControllerClient> client) {
+  client_.Bind(std::move(client));
 
   // Initializes some observers for client.
   if (CastConfigController::Get())
diff --git a/ash/ime/ime_controller.h b/ash/ime/ime_controller.h
index 4edbb237b..d4d3824 100644
--- a/ash/ime/ime_controller.h
+++ b/ash/ime/ime_controller.h
@@ -14,7 +14,10 @@
 #include "ash/public/mojom/ime_info.mojom.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "ui/display/display_observer.h"
 
 namespace ui {
@@ -68,7 +71,7 @@
   }
 
   // Binds the mojo interface to this object.
-  void BindRequest(mojom::ImeControllerRequest request);
+  void BindReceiver(mojo::PendingReceiver<mojom::ImeController> receiver);
 
   // Returns true if switching to next/previous IME is allowed.
   bool CanSwitchIme() const;
@@ -91,7 +94,8 @@
   void SwitchImeWithAccelerator(const ui::Accelerator& accelerator);
 
   // mojom::ImeController:
-  void SetClient(mojom::ImeControllerClientPtr client) override;
+  void SetClient(
+      mojo::PendingRemote<mojom::ImeControllerClient> client) override;
   void RefreshIme(const std::string& current_ime_id,
                   std::vector<mojom::ImeInfoPtr> available_imes,
                   std::vector<mojom::ImeMenuItemPtr> menu_items) override;
@@ -137,11 +141,11 @@
   std::vector<std::string> GetCandidateImesForAccelerator(
       const ui::Accelerator& accelerator) const;
 
-  // Bindings for users of the mojo interface.
-  mojo::BindingSet<mojom::ImeController> bindings_;
+  // Receivers for users of the mojo interface.
+  mojo::ReceiverSet<mojom::ImeController> receivers_;
 
   // Client interface back to IME code in chrome.
-  mojom::ImeControllerClientPtr client_;
+  mojo::Remote<mojom::ImeControllerClient> client_;
 
   // Copy of the current IME so we can return it by reference.
   mojom::ImeInfo current_ime_;
diff --git a/ash/ime/ime_controller_unittest.cc b/ash/ime/ime_controller_unittest.cc
index 67c0e90..3e0d90c 100644
--- a/ash/ime/ime_controller_unittest.cc
+++ b/ash/ime/ime_controller_unittest.cc
@@ -179,7 +179,7 @@
   EXPECT_EQ(0, client.switch_ime_count_);
 
   // After setting the client the requests are forwarded.
-  controller->SetClient(client.CreateInterfacePtr());
+  controller->SetClient(client.CreateRemote());
   controller->SwitchToNextIme();
   controller->FlushMojoForTesting();
   EXPECT_EQ(1, client.next_ime_count_);
@@ -204,7 +204,7 @@
 TEST_F(ImeControllerTest, SwitchImeWithAccelerator) {
   ImeController* controller = Shell::Get()->ime_controller();
   TestImeControllerClient client;
-  controller->SetClient(client.CreateInterfacePtr());
+  controller->SetClient(client.CreateRemote());
 
   const ui::Accelerator convert(ui::VKEY_CONVERT, ui::EF_NONE);
   const ui::Accelerator non_convert(ui::VKEY_NONCONVERT, ui::EF_NONE);
@@ -271,7 +271,7 @@
   controller->SetCapsLockEnabled(true);
   EXPECT_EQ(0, client.set_caps_lock_count_);
 
-  controller->SetClient(client.CreateInterfacePtr());
+  controller->SetClient(client.CreateRemote());
 
   controller->SetCapsLockEnabled(true);
   controller->FlushMojoForTesting();
@@ -359,7 +359,7 @@
   // The controller is already an observer of the display_manager
   ImeController* controller = Shell::Get()->ime_controller();
   TestImeControllerClient client;
-  controller->SetClient(client.CreateInterfacePtr());
+  controller->SetClient(client.CreateRemote());
 
   display::DisplayManager* display_manager = Shell::Get()->display_manager();
   display_manager->SetMultiDisplayMode(display::DisplayManager::MIRRORING);
diff --git a/ash/ime/test_ime_controller_client.cc b/ash/ime/test_ime_controller_client.cc
index f9ee31be..77256368 100644
--- a/ash/ime/test_ime_controller_client.cc
+++ b/ash/ime/test_ime_controller_client.cc
@@ -12,14 +12,13 @@
 
 namespace ash {
 
-TestImeControllerClient::TestImeControllerClient() : binding_(this) {}
+TestImeControllerClient::TestImeControllerClient() = default;
 
 TestImeControllerClient::~TestImeControllerClient() = default;
 
-mojom::ImeControllerClientPtr TestImeControllerClient::CreateInterfacePtr() {
-  mojom::ImeControllerClientPtr ptr;
-  binding_.Bind(mojo::MakeRequest(&ptr));
-  return ptr;
+mojo::PendingRemote<mojom::ImeControllerClient>
+TestImeControllerClient::CreateRemote() {
+  return receiver_.BindNewPipeAndPassRemote();
 }
 
 void TestImeControllerClient::SwitchToNextIme() {
diff --git a/ash/ime/test_ime_controller_client.h b/ash/ime/test_ime_controller_client.h
index 3b044e24..da755589 100644
--- a/ash/ime/test_ime_controller_client.h
+++ b/ash/ime/test_ime_controller_client.h
@@ -7,7 +7,8 @@
 
 #include "ash/public/mojom/ime_controller.mojom.h"
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 namespace ash {
 
@@ -16,7 +17,7 @@
   TestImeControllerClient();
   ~TestImeControllerClient() override;
 
-  mojom::ImeControllerClientPtr CreateInterfacePtr();
+  mojo::PendingRemote<mojom::ImeControllerClient> CreateRemote();
 
   // mojom::ImeControllerClient:
   void SwitchToNextIme() override;
@@ -43,7 +44,7 @@
   int show_mode_indicator_count_ = 0;
 
  private:
-  mojo::Binding<mojom::ImeControllerClient> binding_;
+  mojo::Receiver<mojom::ImeControllerClient> receiver_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TestImeControllerClient);
 };
diff --git a/ash/keyboard/virtual_keyboard_controller_unittest.cc b/ash/keyboard/virtual_keyboard_controller_unittest.cc
index 8914470..4303fb8 100644
--- a/ash/keyboard/virtual_keyboard_controller_unittest.cc
+++ b/ash/keyboard/virtual_keyboard_controller_unittest.cc
@@ -93,7 +93,7 @@
 
   // Set up a mock ImeControllerClient to test keyset changes.
   TestImeControllerClient client;
-  Shell::Get()->ime_controller()->SetClient(client.CreateInterfacePtr());
+  Shell::Get()->ime_controller()->SetClient(client.CreateRemote());
 
   // Should show the keyboard without messing with accessibility prefs.
   GetVirtualKeyboardController()->ForceShowKeyboardWithKeyset(
@@ -129,7 +129,7 @@
        ForceToShowKeyboardWithKeysetWhenKeyboardIsDisabled) {
   // Set up a mock ImeControllerClient to test keyset changes.
   TestImeControllerClient client;
-  Shell::Get()->ime_controller()->SetClient(client.CreateInterfacePtr());
+  Shell::Get()->ime_controller()->SetClient(client.CreateRemote());
 
   // Should show the keyboard by enabling it temporarily.
   EXPECT_FALSE(keyboard_ui_controller()->IsEnabled());
@@ -170,7 +170,7 @@
        ForceToShowKeyboardWithKeysetTemporaryHide) {
   // Set up a mock ImeControllerClient to test keyset changes.
   TestImeControllerClient client;
-  Shell::Get()->ime_controller()->SetClient(client.CreateInterfacePtr());
+  Shell::Get()->ime_controller()->SetClient(client.CreateRemote());
 
   // Should show the keyboard by enabling it temporarily.
   GetVirtualKeyboardController()->ForceShowKeyboardWithKeyset(
diff --git a/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc b/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc
index 39bd02c..9167844 100644
--- a/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc
+++ b/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc
@@ -98,7 +98,7 @@
     InitializeTabletPowerButtonState();
 
     Shell::Get()->tray_action()->SetClient(
-        tray_action_client_.CreateInterfacePtrAndBind(),
+        tray_action_client_.CreateRemoteAndBind(),
         mojom::TrayActionState::kAvailable);
     Shell::Get()->tray_action()->FlushMojoForTesting();
     // Run the loop so the lock screen note display state handler picks up
diff --git a/ash/lock_screen_action/lock_screen_note_launcher_unittest.cc b/ash/lock_screen_action/lock_screen_note_launcher_unittest.cc
index 3962977..5f4b8eb 100644
--- a/ash/lock_screen_action/lock_screen_note_launcher_unittest.cc
+++ b/ash/lock_screen_action/lock_screen_note_launcher_unittest.cc
@@ -27,7 +27,7 @@
 TEST_F(LockScreenNoteLauncherTest, LaunchSuccess) {
   TrayAction* tray_action = Shell::Get()->tray_action();
   TestTrayActionClient action_client;
-  tray_action->SetClient(action_client.CreateInterfacePtrAndBind(),
+  tray_action->SetClient(action_client.CreateRemoteAndBind(),
                          mojom::TrayActionState::kAvailable);
 
   EXPECT_TRUE(LockScreenNoteLauncher::CanAttemptLaunch());
@@ -58,7 +58,7 @@
 TEST_F(LockScreenNoteLauncherTest, LaunchFailure) {
   TrayAction* tray_action = Shell::Get()->tray_action();
   TestTrayActionClient action_client;
-  tray_action->SetClient(action_client.CreateInterfacePtrAndBind(),
+  tray_action->SetClient(action_client.CreateRemoteAndBind(),
                          mojom::TrayActionState::kAvailable);
 
   EXPECT_TRUE(LockScreenNoteLauncher::CanAttemptLaunch());
@@ -89,7 +89,7 @@
 TEST_F(LockScreenNoteLauncherTest, LaunchNotRequestedInUnavailableStates) {
   TrayAction* tray_action = Shell::Get()->tray_action();
   TestTrayActionClient action_client;
-  tray_action->SetClient(action_client.CreateInterfacePtrAndBind(),
+  tray_action->SetClient(action_client.CreateRemoteAndBind(),
                          mojom::TrayActionState::kLaunching);
 
   EXPECT_FALSE(LockScreenNoteLauncher::CanAttemptLaunch());
diff --git a/ash/login/ui/lock_contents_view_unittest.cc b/ash/login/ui/lock_contents_view_unittest.cc
index bd76c5b..8654466 100644
--- a/ash/login/ui/lock_contents_view_unittest.cc
+++ b/ash/login/ui/lock_contents_view_unittest.cc
@@ -1883,7 +1883,7 @@
        ToggleNoteActionVisibilityOnAuthEnabledChanged) {
   auto* tray_action = Shell::Get()->tray_action();
   TestTrayActionClient action_client;
-  tray_action->SetClient(action_client.CreateInterfacePtrAndBind(),
+  tray_action->SetClient(action_client.CreateRemoteAndBind(),
                          mojom::TrayActionState::kAvailable);
   auto* contents = new LockContentsView(
       Shell::Get()->tray_action()->GetLockScreenNoteState(),
diff --git a/ash/login/ui/note_action_launch_button_unittest.cc b/ash/login/ui/note_action_launch_button_unittest.cc
index e9c78f2..df179ea 100644
--- a/ash/login/ui/note_action_launch_button_unittest.cc
+++ b/ash/login/ui/note_action_launch_button_unittest.cc
@@ -43,7 +43,7 @@
     LoginTestBase::SetUp();
 
     Shell::Get()->tray_action()->SetClient(
-        tray_action_client_.CreateInterfacePtrAndBind(),
+        tray_action_client_.CreateRemoteAndBind(),
         mojom::TrayActionState::kAvailable);
   }
 
diff --git a/ash/mojo_interface_factory.cc b/ash/mojo_interface_factory.cc
index e8f60ed4..52464b2 100644
--- a/ash/mojo_interface_factory.cc
+++ b/ash/mojo_interface_factory.cc
@@ -12,6 +12,7 @@
 #include "ash/login/login_screen_controller.h"
 #include "ash/media/media_controller_impl.h"
 #include "ash/public/cpp/ash_features.h"
+#include "ash/public/mojom/cros_display_config.mojom.h"
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
 #include "ash/tray_action/tray_action.h"
@@ -19,6 +20,7 @@
 #include "base/lazy_instance.h"
 #include "base/single_thread_task_runner.h"
 #include "chromeos/constants/chromeos_features.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 
 namespace ash {
 namespace mojo_interface_factory {
@@ -27,20 +29,22 @@
 base::LazyInstance<RegisterInterfacesCallback>::Leaky
     g_register_interfaces_callback = LAZY_INSTANCE_INITIALIZER;
 
-void BindCrosDisplayConfigControllerRequestOnMainThread(
-    mojom::CrosDisplayConfigControllerRequest request) {
+void BindCrosDisplayConfigControllerReceiverOnMainThread(
+    mojo::PendingReceiver<mojom::CrosDisplayConfigController> receiver) {
   if (Shell::HasInstance())
-    Shell::Get()->cros_display_config()->BindRequest(std::move(request));
+    Shell::Get()->cros_display_config()->BindReceiver(std::move(receiver));
 }
 
-void BindImeControllerRequestOnMainThread(mojom::ImeControllerRequest request) {
+void BindImeControllerReceiverOnMainThread(
+    mojo::PendingReceiver<mojom::ImeController> receiver) {
   if (Shell::HasInstance())
-    Shell::Get()->ime_controller()->BindRequest(std::move(request));
+    Shell::Get()->ime_controller()->BindReceiver(std::move(receiver));
 }
 
-void BindTrayActionRequestOnMainThread(mojom::TrayActionRequest request) {
+void BindTrayActionReceiverOnMainThread(
+    mojo::PendingReceiver<mojom::TrayAction> receiver) {
   if (Shell::HasInstance())
-    Shell::Get()->tray_action()->BindRequest(std::move(request));
+    Shell::Get()->tray_action()->BindReceiver(std::move(receiver));
 }
 
 }  // namespace
@@ -49,13 +53,13 @@
     service_manager::BinderRegistry* registry,
     scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner) {
   registry->AddInterface(
-      base::BindRepeating(&BindCrosDisplayConfigControllerRequestOnMainThread),
+      base::BindRepeating(&BindCrosDisplayConfigControllerReceiverOnMainThread),
       main_thread_task_runner);
   registry->AddInterface(
-      base::BindRepeating(&BindImeControllerRequestOnMainThread),
+      base::BindRepeating(&BindImeControllerReceiverOnMainThread),
       main_thread_task_runner);
   registry->AddInterface(
-      base::BindRepeating(&BindTrayActionRequestOnMainThread),
+      base::BindRepeating(&BindTrayActionReceiverOnMainThread),
       main_thread_task_runner);
 
   // Inject additional optional interfaces.
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 10966351..69a3202 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -324,6 +324,7 @@
     ":cpp",
     "//base",
     "//base/test:test_support",
+    "//mojo/public/cpp/bindings",
     "//testing/gtest",
     "//ui/aura:test_support",
     "//ui/compositor_extra",
diff --git a/ash/public/cpp/default_scale_factor_retriever.cc b/ash/public/cpp/default_scale_factor_retriever.cc
index a7a7a8b..617f436f 100644
--- a/ash/public/cpp/default_scale_factor_retriever.cc
+++ b/ash/public/cpp/default_scale_factor_retriever.cc
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 #include "ash/public/cpp/default_scale_factor_retriever.h"
+
+#include <utility>
+
 #include "ash/public/mojom/constants.mojom.h"
 #include "base/bind.h"
 
@@ -11,8 +14,9 @@
 DefaultScaleFactorRetriever::DefaultScaleFactorRetriever() {}
 
 void DefaultScaleFactorRetriever::Start(
-    ash::mojom::CrosDisplayConfigControllerPtr cros_display_config) {
-  cros_display_config_ = std::move(cros_display_config);
+    mojo::PendingRemote<ash::mojom::CrosDisplayConfigController>
+        cros_display_config) {
+  cros_display_config_.Bind(std::move(cros_display_config));
   auto callback = base::BindOnce(
       &DefaultScaleFactorRetriever::OnDefaultScaleFactorRetrieved,
       weak_ptr_factory_.GetWeakPtr());
diff --git a/ash/public/cpp/default_scale_factor_retriever.h b/ash/public/cpp/default_scale_factor_retriever.h
index 06546fb0..32593a0 100644
--- a/ash/public/cpp/default_scale_factor_retriever.h
+++ b/ash/public/cpp/default_scale_factor_retriever.h
@@ -10,6 +10,8 @@
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace ash {
 
@@ -27,7 +29,8 @@
   ~DefaultScaleFactorRetriever();
 
   // Start the query process.
-  void Start(mojom::CrosDisplayConfigControllerPtr cros_display_config);
+  void Start(mojo::PendingRemote<mojom::CrosDisplayConfigController>
+                 cros_display_config);
 
   // Get the default scale factor. The scale factor will be passed
   // as an argument to the |callback|. The callback may be call synchronously
@@ -45,7 +48,7 @@
   void OnDefaultScaleFactorRetrieved(float scale_factor);
 
   float default_scale_factor_ = -1.f;
-  mojom::CrosDisplayConfigControllerPtr cros_display_config_;
+  mojo::Remote<mojom::CrosDisplayConfigController> cros_display_config_;
   GetDefaultScaleFactorCallback callback_;
 
   // WeakPtrFactory to use callbacks.
diff --git a/ash/public/cpp/default_scale_factor_retriever_unittest.cc b/ash/public/cpp/default_scale_factor_retriever_unittest.cc
index a4b41e6d..7a383b0 100644
--- a/ash/public/cpp/default_scale_factor_retriever_unittest.cc
+++ b/ash/public/cpp/default_scale_factor_retriever_unittest.cc
@@ -8,7 +8,9 @@
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/display/display.h"
 
@@ -20,17 +22,17 @@
  public:
   static constexpr int64_t kFakeDisplayId = 1;
 
-  TestCrosDisplayConfig() : binding_(this) {}
+  TestCrosDisplayConfig() = default;
 
-  ash::mojom::CrosDisplayConfigControllerPtr CreateInterfacePtrAndBind() {
-    ash::mojom::CrosDisplayConfigControllerPtr ptr;
-    binding_.Bind(mojo::MakeRequest(&ptr));
-    return ptr;
+  mojo::PendingRemote<ash::mojom::CrosDisplayConfigController>
+  CreateRemoteAndBind() {
+    return receiver_.BindNewPipeAndPassRemote();
   }
 
   // ash::mojom::CrosDisplayConfigController:
-  void AddObserver(ash::mojom::CrosDisplayConfigObserverAssociatedPtrInfo
-                       observer) override {}
+  void AddObserver(
+      mojo::PendingAssociatedRemote<ash::mojom::CrosDisplayConfigObserver>
+          observer) override {}
   void GetDisplayLayoutInfo(GetDisplayLayoutInfoCallback callback) override {}
   void SetDisplayLayoutInfo(ash::mojom::DisplayLayoutInfoPtr info,
                             SetDisplayLayoutInfoCallback callback) override {}
@@ -62,7 +64,7 @@
                         TouchCalibrationCallback callback) override {}
 
  private:
-  mojo::Binding<ash::mojom::CrosDisplayConfigController> binding_;
+  mojo::Receiver<ash::mojom::CrosDisplayConfigController> receiver_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TestCrosDisplayConfig);
 };
@@ -88,7 +90,7 @@
     result[0] = default_scale_factor;
   };
   float result1[1] = {0};
-  retriever->Start(display_config->CreateInterfacePtrAndBind());
+  retriever->Start(display_config->CreateRemoteAndBind());
   retriever->GetDefaultScaleFactor(base::BindOnce(callback, result1));
   float result2[1] = {0};
   // This will cancel the 1st callback.
@@ -122,7 +124,7 @@
     result[0] = default_scale_factor;
   };
   float result[1] = {0};
-  retriever->Start(display_config->CreateInterfacePtrAndBind());
+  retriever->Start(display_config->CreateRemoteAndBind());
   retriever->GetDefaultScaleFactor(base::BindOnce(callback, result));
   retriever->CancelCallback();
   EXPECT_EQ(0.f, result[0]);
diff --git a/ash/public/mojom/cros_display_config.mojom b/ash/public/mojom/cros_display_config.mojom
index 774f0533..a3b3004 100644
--- a/ash/public/mojom/cros_display_config.mojom
+++ b/ash/public/mojom/cros_display_config.mojom
@@ -231,7 +231,7 @@
 interface CrosDisplayConfigController {
   // Observers are notified when the display layout or any display properties
   // change.
-  AddObserver(associated CrosDisplayConfigObserver observer);
+  AddObserver(pending_associated_remote<CrosDisplayConfigObserver> observer);
 
   // Returns the display layout info, including the list of layouts.
   GetDisplayLayoutInfo() => (DisplayLayoutInfo info);
diff --git a/ash/public/mojom/ime_controller.mojom b/ash/public/mojom/ime_controller.mojom
index 9edb3a6..ad682e57 100644
--- a/ash/public/mojom/ime_controller.mojom
+++ b/ash/public/mojom/ime_controller.mojom
@@ -12,7 +12,7 @@
 // Interface for ash client (e.g. Chrome) to send input method info to ash.
 interface ImeController {
   // Sets the client interface.
-  SetClient(ImeControllerClient client);
+  SetClient(pending_remote<ImeControllerClient> client);
 
   // Updates the cached IME information and refreshes the IME menus.
   // |current_ime_id| is empty when there is no active IME yet.
diff --git a/ash/public/mojom/tray_action.mojom b/ash/public/mojom/tray_action.mojom
index e366f9a..4c951576 100644
--- a/ash/public/mojom/tray_action.mojom
+++ b/ash/public/mojom/tray_action.mojom
@@ -84,7 +84,8 @@
   // Sets the client to be used to handle action requests.
   // |lock_screen_note_state|: The current lock screen note action state
   //     associated with the client.
-  SetClient(TrayActionClient client, TrayActionState lock_screen_note_state);
+  SetClient(pending_remote<TrayActionClient> client,
+            TrayActionState lock_screen_note_state);
 
   // Updates action state for the lock screen note action. If called with no
   // client set, the state change will not take effect until a client is set.
diff --git a/ash/shelf/login_shelf_view_unittest.cc b/ash/shelf/login_shelf_view_unittest.cc
index a3b5021..61ec165b 100644
--- a/ash/shelf/login_shelf_view_unittest.cc
+++ b/ash/shelf/login_shelf_view_unittest.cc
@@ -69,7 +69,7 @@
     LoginTestBase::SetUp();
     login_shelf_view_ = GetPrimaryShelf()->shelf_widget()->login_shelf_view();
     Shell::Get()->tray_action()->SetClient(
-        tray_action_client_.CreateInterfacePtrAndBind(),
+        tray_action_client_.CreateRemoteAndBind(),
         mojom::TrayActionState::kNotAvailable);
     // Set initial states.
     NotifySessionStateChanged(SessionState::OOBE);
diff --git a/ash/system/ime_menu/ime_menu_tray_unittest.cc b/ash/system/ime_menu/ime_menu_tray_unittest.cc
index c15df66..058e593 100644
--- a/ash/system/ime_menu/ime_menu_tray_unittest.cc
+++ b/ash/system/ime_menu/ime_menu_tray_unittest.cc
@@ -282,7 +282,7 @@
   EXPECT_TRUE(IsBubbleShown());
 
   TestImeControllerClient client;
-  Shell::Get()->ime_controller()->SetClient(client.CreateInterfacePtr());
+  Shell::Get()->ime_controller()->SetClient(client.CreateRemote());
   GetTray()->ShowKeyboardWithKeyset(
       chromeos::input_method::mojom::ImeKeyset::kEmoji);
 
diff --git a/ash/tray_action/test_tray_action_client.cc b/ash/tray_action/test_tray_action_client.cc
index 8205889..59bee2d 100644
--- a/ash/tray_action/test_tray_action_client.cc
+++ b/ash/tray_action/test_tray_action_client.cc
@@ -4,11 +4,11 @@
 
 #include "ash/tray_action/test_tray_action_client.h"
 
-#include "mojo/public/cpp/bindings/interface_request.h"
+#include "ash/public/mojom/tray_action.mojom.h"
 
 namespace ash {
 
-TestTrayActionClient::TestTrayActionClient() : binding_(this) {}
+TestTrayActionClient::TestTrayActionClient() = default;
 
 TestTrayActionClient::~TestTrayActionClient() = default;
 
@@ -27,10 +27,11 @@
   close_note_reasons_.push_back(reason);
 }
 
-mojom::TrayActionClientPtr TestTrayActionClient::CreateInterfacePtrAndBind() {
-  mojom::TrayActionClientPtr ptr;
-  binding_.Bind(mojo::MakeRequest(&ptr));
-  return ptr;
+mojo::PendingRemote<mojom::TrayActionClient>
+TestTrayActionClient::CreateRemoteAndBind() {
+  mojo::PendingRemote<mojom::TrayActionClient> remote;
+  receiver_.Bind(remote.InitWithNewPipeAndPassReceiver());
+  return remote;
 }
 
 }  // namespace ash
diff --git a/ash/tray_action/test_tray_action_client.h b/ash/tray_action/test_tray_action_client.h
index ff6c02af..ae0748a 100644
--- a/ash/tray_action/test_tray_action_client.h
+++ b/ash/tray_action/test_tray_action_client.h
@@ -9,7 +9,8 @@
 
 #include "ash/public/mojom/tray_action.mojom.h"
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 namespace ash {
 
@@ -19,7 +20,7 @@
 
   ~TestTrayActionClient() override;
 
-  mojom::TrayActionClientPtr CreateInterfacePtrAndBind();
+  mojo::PendingRemote<mojom::TrayActionClient> CreateRemoteAndBind();
 
   void ClearRecordedRequests();
 
@@ -37,7 +38,7 @@
   void CloseLockScreenNote(mojom::CloseLockScreenNoteReason reason) override;
 
  private:
-  mojo::Binding<mojom::TrayActionClient> binding_;
+  mojo::Receiver<mojom::TrayActionClient> receiver_{this};
 
   std::vector<mojom::LockScreenNoteOrigin> note_origins_;
   std::vector<mojom::CloseLockScreenNoteReason> close_note_reasons_;
diff --git a/ash/tray_action/tray_action.cc b/ash/tray_action/tray_action.cc
index fb5cce74..aae9360 100644
--- a/ash/tray_action/tray_action.cc
+++ b/ash/tray_action/tray_action.cc
@@ -30,8 +30,9 @@
   observers_.RemoveObserver(observer);
 }
 
-void TrayAction::BindRequest(mojom::TrayActionRequest request) {
-  bindings_.AddBinding(this, std::move(request));
+void TrayAction::BindReceiver(
+    mojo::PendingReceiver<mojom::TrayAction> receiver) {
+  receivers_.Add(this, std::move(receiver));
 }
 
 mojom::TrayActionState TrayAction::GetLockScreenNoteState() const {
@@ -44,23 +45,25 @@
   return GetLockScreenNoteState() == mojom::TrayActionState::kActive;
 }
 
-void TrayAction::SetClient(mojom::TrayActionClientPtr tray_action_client,
-                           mojom::TrayActionState lock_screen_note_state) {
+void TrayAction::SetClient(
+    mojo::PendingRemote<mojom::TrayActionClient> tray_action_client,
+    mojom::TrayActionState lock_screen_note_state) {
   mojom::TrayActionState old_lock_screen_note_state = GetLockScreenNoteState();
 
-  tray_action_client_ = std::move(tray_action_client);
+  if (tray_action_client) {
+    tray_action_client_.Bind(std::move(tray_action_client));
 
-  if (tray_action_client_) {
     // Makes sure the state is updated in case the connection is lost.
-    tray_action_client_.set_connection_error_handler(
-        base::Bind(&TrayAction::SetClient, base::Unretained(this), nullptr,
-                   mojom::TrayActionState::kNotAvailable));
+    tray_action_client_.set_disconnect_handler(
+        base::Bind(&TrayAction::SetClient, base::Unretained(this),
+                   mojo::NullRemote(), mojom::TrayActionState::kNotAvailable));
     lock_screen_note_state_ = lock_screen_note_state;
 
     lock_screen_note_display_state_handler_ =
         std::make_unique<LockScreenNoteDisplayStateHandler>(
             backlights_forced_off_setter_);
   } else {
+    tray_action_client_.reset();
     lock_screen_note_display_state_handler_.reset();
   }
 
diff --git a/ash/tray_action/tray_action.h b/ash/tray_action/tray_action.h
index a4f4572..e24a450c 100644
--- a/ash/tray_action/tray_action.h
+++ b/ash/tray_action/tray_action.h
@@ -12,7 +12,10 @@
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/scoped_observer.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/input_device_event_observer.h"
 
@@ -49,7 +52,7 @@
   void AddObserver(TrayActionObserver* observer);
   void RemoveObserver(TrayActionObserver* observer);
 
-  void BindRequest(mojom::TrayActionRequest request);
+  void BindReceiver(mojo::PendingReceiver<mojom::TrayAction> receiver);
 
   // Gets last known handler state for the lock screen note action.
   // It will return kNotAvailable if an action handler has not been set using
@@ -67,7 +70,7 @@
   void CloseLockScreenNote(mojom::CloseLockScreenNoteReason reason);
 
   // mojom::TrayAction:
-  void SetClient(mojom::TrayActionClientPtr action_handler,
+  void SetClient(mojo::PendingRemote<mojom::TrayActionClient> action_handler,
                  mojom::TrayActionState lock_screen_note_state) override;
   void UpdateLockScreenNoteState(mojom::TrayActionState state) override;
 
@@ -92,10 +95,10 @@
 
   base::ObserverList<TrayActionObserver>::Unchecked observers_;
 
-  // Bindings for users of the mojo interface.
-  mojo::BindingSet<mojom::TrayAction> bindings_;
+  // Receivers for users of the mojo interface.
+  mojo::ReceiverSet<mojom::TrayAction> receivers_;
 
-  mojom::TrayActionClientPtr tray_action_client_;
+  mojo::Remote<mojom::TrayActionClient> tray_action_client_;
 
   ScopedObserver<ui::DeviceDataManager, ui::InputDeviceEventObserver>
       stylus_observer_{this};
diff --git a/ash/tray_action/tray_action_unittest.cc b/ash/tray_action/tray_action_unittest.cc
index c83e2b1..6360a1e 100644
--- a/ash/tray_action/tray_action_unittest.cc
+++ b/ash/tray_action/tray_action_unittest.cc
@@ -69,7 +69,7 @@
 
   std::unique_ptr<TestTrayActionClient> action_client =
       std::make_unique<TestTrayActionClient>();
-  tray_action->SetClient(action_client->CreateInterfacePtrAndBind(),
+  tray_action->SetClient(action_client->CreateRemoteAndBind(),
                          TrayActionState::kLaunching);
 
   EXPECT_EQ(TrayActionState::kLaunching, tray_action->GetLockScreenNoteState());
@@ -91,7 +91,7 @@
 
   ScopedTestStateObserver observer(tray_action);
   TestTrayActionClient action_client;
-  tray_action->SetClient(action_client.CreateInterfacePtrAndBind(),
+  tray_action->SetClient(action_client.CreateRemoteAndBind(),
                          TrayActionState::kAvailable);
 
   EXPECT_EQ(TrayActionState::kAvailable, tray_action->GetLockScreenNoteState());
@@ -105,7 +105,7 @@
   ScopedTestStateObserver observer(tray_action);
   std::unique_ptr<TestTrayActionClient> action_client(
       new TestTrayActionClient());
-  tray_action->SetClient(action_client->CreateInterfacePtrAndBind(),
+  tray_action->SetClient(action_client->CreateRemoteAndBind(),
                          TrayActionState::kAvailable);
 
   EXPECT_EQ(TrayActionState::kAvailable, tray_action->GetLockScreenNoteState());
@@ -127,7 +127,7 @@
 
   ScopedTestStateObserver observer(tray_action);
   TestTrayActionClient action_client;
-  tray_action->SetClient(action_client.CreateInterfacePtrAndBind(),
+  tray_action->SetClient(action_client.CreateRemoteAndBind(),
                          TrayActionState::kNotAvailable);
 
   tray_action->UpdateLockScreenNoteState(TrayActionState::kAvailable);
@@ -164,7 +164,7 @@
 
   ScopedTestStateObserver observer(tray_action);
   TestTrayActionClient action_client;
-  tray_action->SetClient(action_client.CreateInterfacePtrAndBind(),
+  tray_action->SetClient(action_client.CreateRemoteAndBind(),
                          TrayActionState::kNotAvailable);
 
   tray_action->UpdateLockScreenNoteState(TrayActionState::kAvailable);
@@ -182,7 +182,7 @@
   TrayAction* tray_action = Shell::Get()->tray_action();
 
   TestTrayActionClient action_client;
-  tray_action->SetClient(action_client.CreateInterfacePtrAndBind(),
+  tray_action->SetClient(action_client.CreateRemoteAndBind(),
                          TrayActionState::kNotAvailable);
 
   EXPECT_TRUE(action_client.note_origins().empty());
@@ -212,7 +212,7 @@
   TrayAction* tray_action = Shell::Get()->tray_action();
 
   TestTrayActionClient action_client;
-  tray_action->SetClient(action_client.CreateInterfacePtrAndBind(),
+  tray_action->SetClient(action_client.CreateRemoteAndBind(),
                          TrayActionState::kNotAvailable);
 
   tray_action->UpdateLockScreenNoteState(TrayActionState::kActive);
diff --git a/ash/wm/lock_action_handler_layout_manager_unittest.cc b/ash/wm/lock_action_handler_layout_manager_unittest.cc
index ffbb8d13..85863220 100644
--- a/ash/wm/lock_action_handler_layout_manager_unittest.cc
+++ b/ash/wm/lock_action_handler_layout_manager_unittest.cc
@@ -136,7 +136,7 @@
 
   void SetUpTrayActionClientAndLockSession(mojom::TrayActionState state) {
     Shell::Get()->tray_action()->SetClient(
-        tray_action_client_.CreateInterfacePtrAndBind(), state);
+        tray_action_client_.CreateRemoteAndBind(), state);
     GetSessionControllerClient()->SetSessionState(
         session_manager::SessionState::LOCKED);
   }
diff --git a/base/allocator/partition_allocator/partition_alloc.cc b/base/allocator/partition_allocator/partition_alloc.cc
index 4b6d55f..297a6bb 100644
--- a/base/allocator/partition_allocator/partition_alloc.cc
+++ b/base/allocator/partition_allocator/partition_alloc.cc
@@ -493,14 +493,14 @@
     size_t slot_index = (reinterpret_cast<char*>(entry) - ptr) / slot_size;
     DCHECK(slot_index < num_slots);
     slot_usage[slot_index] = 0;
-    entry = internal::PartitionFreelistEntry::Transform(entry->next);
+    entry = internal::EncodedPartitionFreelistEntry::Decode(entry->next);
 #if !defined(OS_WIN)
     // If we have a slot where the masked freelist entry is 0, we can actually
     // discard that freelist entry because touching a discarded page is
     // guaranteed to return original content or 0. (Note that this optimization
     // won't fire on big-endian machines because the masking function is
     // negation.)
-    if (!internal::PartitionFreelistEntry::Transform(entry))
+    if (!internal::PartitionFreelistEntry::Encode(entry))
       last_slot = slot_index;
 #endif
   }
@@ -534,25 +534,33 @@
       DCHECK(truncated_slots > 0);
       size_t num_new_entries = 0;
       page->num_unprovisioned_slots += static_cast<uint16_t>(truncated_slots);
+
       // Rewrite the freelist.
-      internal::PartitionFreelistEntry** entry_ptr = &page->freelist_head;
+      internal::PartitionFreelistEntry* head = nullptr;
+      internal::PartitionFreelistEntry* back = head;
       for (size_t slot_index = 0; slot_index < num_slots; ++slot_index) {
         if (slot_usage[slot_index])
           continue;
+
         auto* entry = reinterpret_cast<internal::PartitionFreelistEntry*>(
             ptr + (slot_size * slot_index));
-        *entry_ptr = internal::PartitionFreelistEntry::Transform(entry);
-        entry_ptr = reinterpret_cast<internal::PartitionFreelistEntry**>(entry);
+        if (!head) {
+          head = entry;
+          back = entry;
+        } else {
+          back->next = internal::PartitionFreelistEntry::Encode(entry);
+          back = entry;
+        }
         num_new_entries++;
 #if !defined(OS_WIN)
         last_slot = slot_index;
 #endif
       }
-      // Terminate the freelist chain.
-      *entry_ptr = nullptr;
-      // The freelist head is stored unmasked.
-      page->freelist_head =
-          internal::PartitionFreelistEntry::Transform(page->freelist_head);
+
+      page->freelist_head = head;
+      if (back)
+        back->next = internal::PartitionFreelistEntry::Encode(nullptr);
+
       DCHECK(num_new_entries == num_slots - page->num_allocated_slots);
       // Discard the memory.
       DiscardSystemPages(begin_ptr, unprovisioned_bytes);
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index 8e54f552..2e239a80 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -79,7 +79,7 @@
   page->freelist_head = reinterpret_cast<PartitionFreelistEntry*>(slot);
   PartitionFreelistEntry* next_entry =
       reinterpret_cast<PartitionFreelistEntry*>(slot);
-  next_entry->next = PartitionFreelistEntry::Transform(nullptr);
+  next_entry->next = PartitionFreelistEntry::Encode(nullptr);
 
   DCHECK(!bucket->active_pages_head);
   DCHECK(!bucket->empty_pages_head);
@@ -394,10 +394,10 @@
       freelist_pointer += size;
       PartitionFreelistEntry* next_entry =
           reinterpret_cast<PartitionFreelistEntry*>(freelist_pointer);
-      entry->next = PartitionFreelistEntry::Transform(next_entry);
+      entry->next = PartitionFreelistEntry::Encode(next_entry);
       entry = next_entry;
     }
-    entry->next = PartitionFreelistEntry::Transform(nullptr);
+    entry->next = PartitionFreelistEntry::Encode(nullptr);
   } else {
     page->freelist_head = nullptr;
   }
@@ -555,7 +555,7 @@
   if (LIKELY(new_page->freelist_head != nullptr)) {
     PartitionFreelistEntry* entry = new_page->freelist_head;
     PartitionFreelistEntry* new_head =
-        PartitionFreelistEntry::Transform(entry->next);
+        EncodedPartitionFreelistEntry::Decode(entry->next);
     new_page->freelist_head = new_head;
     new_page->num_allocated_slots++;
     return entry;
diff --git a/base/allocator/partition_allocator/partition_freelist_entry.h b/base/allocator/partition_allocator/partition_freelist_entry.h
index 7e3282e..ce3763b 100644
--- a/base/allocator/partition_allocator/partition_freelist_entry.h
+++ b/base/allocator/partition_allocator/partition_freelist_entry.h
@@ -15,33 +15,56 @@
 namespace base {
 namespace internal {
 
-// TODO(ajwong): Introduce an EncodedFreelistEntry type and then replace
-// Transform() with Encode()/Decode() such that the API provides some static
-// type safety.
-//
-// https://crbug.com/787153
-struct PartitionFreelistEntry {
-  PartitionFreelistEntry* next;
+struct EncodedPartitionFreelistEntry;
 
-  static ALWAYS_INLINE PartitionFreelistEntry* Transform(
+struct PartitionFreelistEntry {
+  EncodedPartitionFreelistEntry* next;
+
+  PartitionFreelistEntry() = delete;
+  ~PartitionFreelistEntry() = delete;
+
+  ALWAYS_INLINE static EncodedPartitionFreelistEntry* Encode(
       PartitionFreelistEntry* ptr) {
-// We use bswap on little endian as a fast mask for two reasons:
-// 1) If an object is freed and its vtable used where the attacker doesn't
-// get the chance to run allocations between the free and use, the vtable
-// dereference is likely to fault.
-// 2) If the attacker has a linear buffer overflow and elects to try and
-// corrupt a freelist pointer, partial pointer overwrite attacks are
-// thwarted.
-// For big endian, similar guarantees are arrived at with a negation.
+    return reinterpret_cast<EncodedPartitionFreelistEntry*>(Transform(ptr));
+  }
+
+ private:
+  friend struct EncodedPartitionFreelistEntry;
+  static ALWAYS_INLINE void* Transform(void* ptr) {
+    // We use bswap on little endian as a fast mask for two reasons:
+    // 1) If an object is freed and its vtable used where the attacker doesn't
+    // get the chance to run allocations between the free and use, the vtable
+    // dereference is likely to fault.
+    // 2) If the attacker has a linear buffer overflow and elects to try and
+    // corrupt a freelist pointer, partial pointer overwrite attacks are
+    // thwarted.
+    // For big endian, similar guarantees are arrived at with a negation.
 #if defined(ARCH_CPU_BIG_ENDIAN)
     uintptr_t masked = ~reinterpret_cast<uintptr_t>(ptr);
 #else
     uintptr_t masked = ByteSwapUintPtrT(reinterpret_cast<uintptr_t>(ptr));
 #endif
-    return reinterpret_cast<PartitionFreelistEntry*>(masked);
+    return reinterpret_cast<void*>(masked);
   }
 };
 
+struct EncodedPartitionFreelistEntry {
+  char scrambled[sizeof(PartitionFreelistEntry*)];
+
+  EncodedPartitionFreelistEntry() = delete;
+  ~EncodedPartitionFreelistEntry() = delete;
+
+  ALWAYS_INLINE static PartitionFreelistEntry* Decode(
+      EncodedPartitionFreelistEntry* ptr) {
+    return reinterpret_cast<PartitionFreelistEntry*>(
+        PartitionFreelistEntry::Transform(ptr));
+  }
+};
+
+static_assert(sizeof(PartitionFreelistEntry) ==
+                  sizeof(EncodedPartitionFreelistEntry),
+              "Should not have padding");
+
 }  // namespace internal
 }  // namespace base
 
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h
index 6926594f..d2e580b 100644
--- a/base/allocator/partition_allocator/partition_page.h
+++ b/base/allocator/partition_allocator/partition_page.h
@@ -244,11 +244,11 @@
   // Catches an immediate double free.
   CHECK(ptr != freelist_head);
   // Look for double free one level deeper in debug.
-  DCHECK(!freelist_head || ptr != internal::PartitionFreelistEntry::Transform(
-                                      freelist_head->next));
+  DCHECK(!freelist_head ||
+         ptr != EncodedPartitionFreelistEntry::Decode(freelist_head->next));
   internal::PartitionFreelistEntry* entry =
       static_cast<internal::PartitionFreelistEntry*>(ptr);
-  entry->next = internal::PartitionFreelistEntry::Transform(freelist_head);
+  entry->next = internal::PartitionFreelistEntry::Encode(freelist_head);
   freelist_head = entry;
   --this->num_allocated_slots;
   if (UNLIKELY(this->num_allocated_slots <= 0)) {
diff --git a/base/allocator/partition_allocator/partition_root_base.h b/base/allocator/partition_allocator/partition_root_base.h
index 9e971f9f..a3f9175 100644
--- a/base/allocator/partition_allocator/partition_root_base.h
+++ b/base/allocator/partition_allocator/partition_root_base.h
@@ -107,8 +107,8 @@
     // the size metadata.
     DCHECK(page->get_raw_size() == 0);
     internal::PartitionFreelistEntry* new_head =
-        internal::PartitionFreelistEntry::Transform(
-            static_cast<internal::PartitionFreelistEntry*>(ret)->next);
+        internal::EncodedPartitionFreelistEntry::Decode(
+            page->freelist_head->next);
     page->freelist_head = new_head;
     page->num_allocated_slots++;
   } else {
diff --git a/base/android/java/src/org/chromium/base/process_launcher/BindService.java b/base/android/java/src/org/chromium/base/process_launcher/BindService.java
index 0829cb6..d6db68c 100644
--- a/base/android/java/src/org/chromium/base/process_launcher/BindService.java
+++ b/base/android/java/src/org/chromium/base/process_launcher/BindService.java
@@ -71,8 +71,13 @@
 
         try {
             return bindServiceByReflection(context, intent, connection, flags, handler);
-        } catch (ReflectiveOperationException e) {
-            return bindServiceByCall(context, intent, connection, flags);
+        } catch (ReflectiveOperationException reflectionException) {
+            try {
+                return bindServiceByCall(context, intent, connection, flags);
+            } catch (RuntimeException runtimeException) {
+                // Include the reflectionException in crash reports.
+                throw new RuntimeException(runtimeException.getMessage(), reflectionException);
+            }
         }
     }
 
diff --git a/base/values.cc b/base/values.cc
index 8421549..6886b84 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -352,6 +352,11 @@
   return list_;
 }
 
+Value::ListStorage Value::TakeList() {
+  CHECK(is_list());
+  return std::exchange(list_, ListStorage());
+}
+
 void Value::Append(bool value) {
   CHECK(is_list());
   list_.emplace_back(value);
@@ -397,6 +402,24 @@
   list_.emplace_back(std::move(value));
 }
 
+bool Value::EraseListIter(ListStorage::const_iterator iter) {
+  CHECK(is_list());
+  if (iter == list_.end())
+    return false;
+
+  list_.erase(iter);
+  return true;
+}
+
+bool Value::EraseListIter(CheckedContiguousConstIterator<Value> iter) {
+  const auto offset = iter - static_cast<const Value*>(this)->GetList().begin();
+  return EraseListIter(list_.begin() + offset);
+}
+
+size_t Value::EraseListValue(const Value& val) {
+  return EraseListValueIf([&val](const Value& other) { return val == other; });
+}
+
 Value* Value::FindKey(StringPiece key) {
   return const_cast<Value*>(static_cast<const Value*>(this)->FindKey(key));
 }
diff --git a/base/values.h b/base/values.h
index c2b68a7..ccf87bfd 100644
--- a/base/values.h
+++ b/base/values.h
@@ -32,6 +32,7 @@
 #include <vector>
 
 #include "base/base_export.h"
+#include "base/containers/checked_iterators.h"
 #include "base/containers/flat_map.h"
 #include "base/containers/span.h"
 #include "base/macros.h"
@@ -180,6 +181,11 @@
   ListStorage& GetList();
   span<const Value> GetList() const;
 
+  // Transfers ownership of the the underlying list to the caller. Subsequent
+  // calls to GetList() will return an empty list.
+  // Note: This CHECKs that type() is Type::LIST.
+  ListStorage TakeList();
+
   // Appends |value| to the end of the list.
   // Note: These CHECK that type() is Type::LIST.
   void Append(bool value);
@@ -192,6 +198,28 @@
   void Append(StringPiece16 value);
   void Append(Value&& value);
 
+  // Erases the Value pointed to by |iter|. Returns false if |iter| is out of
+  // bounds.
+  // Note: This CHECKs that type() is Type::LIST.
+  bool EraseListIter(ListStorage::const_iterator iter);
+  bool EraseListIter(CheckedContiguousConstIterator<Value> iter);
+
+  // Erases all Values that compare equal to |val|. Returns the number of
+  // deleted Values.
+  // Note: This CHECKs that type() is Type::LIST.
+  size_t EraseListValue(const Value& val);
+
+  // Erases all Values for which |pred| returns true. Returns the number of
+  // deleted Values.
+  // Note: This CHECKs that type() is Type::LIST.
+  template <typename Predicate>
+  size_t EraseListValueIf(Predicate pred) {
+    CHECK(is_list());
+    const size_t old_size = list_.size();
+    base::EraseIf(list_, pred);
+    return old_size - list_.size();
+  }
+
   // |FindKey| looks up |key| in the underlying dictionary. If found, it returns
   // a pointer to the element. Otherwise it returns nullptr.
   // returned. Callers are expected to perform a check against null before using
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
index 4cc13d6..2ae7ae83 100644
--- a/base/values_unittest.cc
+++ b/base/values_unittest.cc
@@ -458,6 +458,34 @@
   EXPECT_EQ(123, blank.GetList().back().GetInt());
 }
 
+TEST(ValuesTest, TakeList) {
+  // Prepare a list with a value of each type.
+  ListValue value;
+  value.Append(Value(Value::Type::NONE));
+  value.Append(Value(Value::Type::BOOLEAN));
+  value.Append(Value(Value::Type::INTEGER));
+  value.Append(Value(Value::Type::DOUBLE));
+  value.Append(Value(Value::Type::STRING));
+  value.Append(Value(Value::Type::BINARY));
+  value.Append(Value(Value::Type::LIST));
+  value.Append(Value(Value::Type::DICTIONARY));
+
+  // Take ownership of the list and make sure its contents are what we expect.
+  auto list = value.TakeList();
+  EXPECT_EQ(8u, list.size());
+  EXPECT_TRUE(list[0].is_none());
+  EXPECT_TRUE(list[1].is_bool());
+  EXPECT_TRUE(list[2].is_int());
+  EXPECT_TRUE(list[3].is_double());
+  EXPECT_TRUE(list[4].is_string());
+  EXPECT_TRUE(list[5].is_blob());
+  EXPECT_TRUE(list[6].is_list());
+  EXPECT_TRUE(list[7].is_dict());
+
+  // Validate that |value| no longer contains values.
+  EXPECT_TRUE(value.GetList().empty());
+}
+
 TEST(ValuesTest, Append) {
   ListValue value;
   value.Append(true);
@@ -496,6 +524,67 @@
   EXPECT_TRUE(value.GetList().back().is_list());
 }
 
+TEST(ValuesTest, EraseListIter) {
+  ListValue value;
+  value.Append(1);
+  value.Append(2);
+  value.Append(3);
+
+  EXPECT_TRUE(value.EraseListIter(value.GetList().begin() + 1));
+  EXPECT_EQ(2u, value.GetList().size());
+  EXPECT_EQ(1, value.GetList()[0].GetInt());
+  EXPECT_EQ(3, value.GetList()[1].GetInt());
+
+  EXPECT_TRUE(value.EraseListIter(value.GetList().begin()));
+  EXPECT_EQ(1u, value.GetList().size());
+  EXPECT_EQ(3, value.GetList()[0].GetInt());
+
+  EXPECT_TRUE(value.EraseListIter(value.GetList().begin()));
+  EXPECT_TRUE(value.GetList().empty());
+
+  EXPECT_FALSE(value.EraseListIter(value.GetList().begin()));
+}
+
+TEST(ValuesTest, EraseListValue) {
+  ListValue value;
+  value.Append(1);
+  value.Append(2);
+  value.Append(2);
+  value.Append(3);
+
+  EXPECT_EQ(2u, value.EraseListValue(Value(2)));
+  EXPECT_EQ(2u, value.GetList().size());
+  EXPECT_EQ(1, value.GetList()[0].GetInt());
+  EXPECT_EQ(3, value.GetList()[1].GetInt());
+
+  EXPECT_EQ(1u, value.EraseListValue(Value(1)));
+  EXPECT_EQ(1u, value.GetList().size());
+  EXPECT_EQ(3, value.GetList()[0].GetInt());
+
+  EXPECT_EQ(1u, value.EraseListValue(Value(3)));
+  EXPECT_TRUE(value.GetList().empty());
+
+  EXPECT_EQ(0u, value.EraseListValue(Value(3)));
+}
+
+TEST(ValuesTest, EraseListValueIf) {
+  ListValue value;
+  value.Append(1);
+  value.Append(2);
+  value.Append(2);
+  value.Append(3);
+
+  EXPECT_EQ(3u, value.EraseListValueIf(
+                    [](const auto& val) { return val >= Value(2); }));
+  EXPECT_EQ(1u, value.GetList().size());
+  EXPECT_EQ(1, value.GetList()[0].GetInt());
+
+  EXPECT_EQ(1u, value.EraseListValueIf([](const auto& val) { return true; }));
+  EXPECT_TRUE(value.GetList().empty());
+
+  EXPECT_EQ(0u, value.EraseListValueIf([](const auto& val) { return true; }));
+}
+
 TEST(ValuesTest, FindKey) {
   Value::DictStorage storage;
   storage.emplace("foo", std::make_unique<Value>("bar"));
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 1271c55..763dfeab 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8899584365969244960
\ No newline at end of file
+8899533185681552544
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 6df2072..c10ecab2 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8899592309896206816
\ No newline at end of file
+8899530595868213136
\ No newline at end of file
diff --git a/cc/metrics/compositor_frame_reporter.cc b/cc/metrics/compositor_frame_reporter.cc
index 0f0dbf85..fbc196e 100644
--- a/cc/metrics/compositor_frame_reporter.cc
+++ b/cc/metrics/compositor_frame_reporter.cc
@@ -153,6 +153,17 @@
   EndCurrentStage(frame_termination_time_);
 }
 
+void CompositorFrameReporter::OnFinishImplFrame(base::TimeTicks timestamp) {
+  DCHECK(!did_finish_impl_frame_);
+
+  did_finish_impl_frame_ = true;
+  impl_frame_finish_time_ = timestamp;
+}
+
+void CompositorFrameReporter::OnAbortBeginMainFrame() {
+  did_abort_main_frame_ = false;
+}
+
 void CompositorFrameReporter::SetVizBreakdown(
     const viz::FrameTimingDetails& viz_breakdown) {
   DCHECK(current_stage_.viz_breakdown.received_compositor_frame_timestamp
diff --git a/cc/metrics/compositor_frame_reporter.h b/cc/metrics/compositor_frame_reporter.h
index ad2b53e..79cbd089 100644
--- a/cc/metrics/compositor_frame_reporter.h
+++ b/cc/metrics/compositor_frame_reporter.h
@@ -111,6 +111,14 @@
 
   int StageHistorySizeForTesting() { return stage_history_.size(); }
 
+  void OnFinishImplFrame(base::TimeTicks timestamp);
+  void OnAbortBeginMainFrame();
+  bool did_finish_impl_frame() const { return did_finish_impl_frame_; }
+  bool did_abort_main_frame() const { return did_abort_main_frame_; }
+  base::TimeTicks impl_frame_finish_time() const {
+    return impl_frame_finish_time_;
+  }
+
  protected:
   struct StageData {
     StageType stage_type;
@@ -161,6 +169,14 @@
       FrameTerminationStatus::kUnknown;
 
   const base::flat_set<FrameSequenceTrackerType>* active_trackers_;
+
+  // Indicates if work on Impl frame is finished.
+  bool did_finish_impl_frame_ = false;
+  // Indicates if main frame is aborted after begin.
+  bool did_abort_main_frame_ = false;
+  // The time that work on Impl frame is finished. It's only valid if the
+  // reporter is in a stage other than begin impl frame.
+  base::TimeTicks impl_frame_finish_time_;
 };
 }  // namespace cc
 
diff --git a/cc/metrics/compositor_frame_reporting_controller.cc b/cc/metrics/compositor_frame_reporting_controller.cc
index 0fea655c..760207b 100644
--- a/cc/metrics/compositor_frame_reporting_controller.cc
+++ b/cc/metrics/compositor_frame_reporting_controller.cc
@@ -59,43 +59,60 @@
   std::unique_ptr<CompositorFrameReporter> reporter =
       std::make_unique<CompositorFrameReporter>(&active_trackers_,
                                                 is_single_threaded_);
-  reporter->StartStage(
-      CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
-      begin_time);
+  reporter->StartStage(StageType::kBeginImplFrameToSendBeginMainFrame,
+                       begin_time);
   reporters_[PipelineStage::kBeginImplFrame] = std::move(reporter);
 }
 
 void CompositorFrameReportingController::WillBeginMainFrame() {
-  DCHECK(reporters_[PipelineStage::kBeginImplFrame]);
-  // We need to use .get() below because operator<< in std::unique_ptr is a
-  // C++20 feature.
-  DCHECK_NE(reporters_[PipelineStage::kBeginMainFrame].get(),
-            reporters_[PipelineStage::kBeginImplFrame].get());
-  reporters_[PipelineStage::kBeginImplFrame]->StartStage(
-      CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now());
-  AdvanceReporterStage(PipelineStage::kBeginImplFrame,
-                       PipelineStage::kBeginMainFrame);
+  if (reporters_[PipelineStage::kBeginImplFrame]) {
+    // We need to use .get() below because operator<< in std::unique_ptr is a
+    // C++20 feature.
+    DCHECK_NE(reporters_[PipelineStage::kBeginMainFrame].get(),
+              reporters_[PipelineStage::kBeginImplFrame].get());
+    reporters_[PipelineStage::kBeginImplFrame]->StartStage(
+        StageType::kSendBeginMainFrameToCommit, Now());
+    AdvanceReporterStage(PipelineStage::kBeginImplFrame,
+                         PipelineStage::kBeginMainFrame);
+  } else {
+    // In this case we have already submitted the ImplFrame, but we received
+    // beginMain frame before next BeginImplFrame (Not reached the ImplFrame
+    // deadline yet). So will start a new reporter at BeginMainFrame.
+    std::unique_ptr<CompositorFrameReporter> reporter =
+        std::make_unique<CompositorFrameReporter>(&active_trackers_,
+                                                  is_single_threaded_);
+    reporter->StartStage(StageType::kSendBeginMainFrameToCommit, Now());
+    reporters_[PipelineStage::kBeginMainFrame] = std::move(reporter);
+  }
 }
 
 void CompositorFrameReportingController::BeginMainFrameAborted() {
   DCHECK(reporters_[PipelineStage::kBeginMainFrame]);
-  std::unique_ptr<CompositorFrameReporter> aborted_frame_reporter =
-      std::move(reporters_[PipelineStage::kBeginMainFrame]);
-  aborted_frame_reporter->TerminateFrame(
-      CompositorFrameReporter::FrameTerminationStatus::kMainFrameAborted,
-      Now());
+
+  auto& begin_main_reporter = reporters_[PipelineStage::kBeginMainFrame];
+  begin_main_reporter->OnAbortBeginMainFrame();
+
+  // If the main-frame was aborted (e.g. there was no visible update), then
+  // advance to activate stage if the compositor has already made changes to
+  // the active tree (i.e. if impl-frame has finished).
+  if (begin_main_reporter->did_finish_impl_frame()) {
+    begin_main_reporter->StartStage(
+        StageType::kEndActivateToSubmitCompositorFrame, Now());
+    AdvanceReporterStage(PipelineStage::kBeginMainFrame,
+                         PipelineStage::kActivate);
+  }
 }
 
 void CompositorFrameReportingController::WillCommit() {
   DCHECK(reporters_[PipelineStage::kBeginMainFrame]);
-  reporters_[PipelineStage::kBeginMainFrame]->StartStage(
-      CompositorFrameReporter::StageType::kCommit, Now());
+  reporters_[PipelineStage::kBeginMainFrame]->StartStage(StageType::kCommit,
+                                                         Now());
 }
 
 void CompositorFrameReportingController::DidCommit() {
   DCHECK(reporters_[PipelineStage::kBeginMainFrame]);
   reporters_[PipelineStage::kBeginMainFrame]->StartStage(
-      CompositorFrameReporter::StageType::kEndCommitToActivation, Now());
+      StageType::kEndCommitToActivation, Now());
   AdvanceReporterStage(PipelineStage::kBeginMainFrame, PipelineStage::kCommit);
 }
 
@@ -109,8 +126,7 @@
   DCHECK(reporters_[PipelineStage::kCommit] || next_activate_has_invalidation_);
   if (!reporters_[PipelineStage::kCommit])
     return;
-  reporters_[PipelineStage::kCommit]->StartStage(
-      CompositorFrameReporter::StageType::kActivation, Now());
+  reporters_[PipelineStage::kCommit]->StartStage(StageType::kActivation, Now());
 }
 
 void CompositorFrameReportingController::DidActivate() {
@@ -119,25 +135,57 @@
   if (!reporters_[PipelineStage::kCommit])
     return;
   reporters_[PipelineStage::kCommit]->StartStage(
-      CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
-      Now());
+      StageType::kEndActivateToSubmitCompositorFrame, Now());
   AdvanceReporterStage(PipelineStage::kCommit, PipelineStage::kActivate);
 }
 
 void CompositorFrameReportingController::DidSubmitCompositorFrame(
     uint32_t frame_token) {
+  // If there is no reporter in active stage and there exists a finished
+  // BeginImplFrame reporter (i.e. if impl-frame has finished), then advance it
+  // to the activate stage.
+  if (!reporters_[PipelineStage::kActivate] &&
+      reporters_[PipelineStage::kBeginImplFrame]) {
+    auto& begin_impl_frame = reporters_[PipelineStage::kBeginImplFrame];
+    if (begin_impl_frame->did_finish_impl_frame()) {
+      begin_impl_frame->StartStage(
+          StageType::kEndActivateToSubmitCompositorFrame,
+          begin_impl_frame->impl_frame_finish_time());
+      AdvanceReporterStage(PipelineStage::kBeginImplFrame,
+                           PipelineStage::kActivate);
+    }
+  }
+
   if (!reporters_[PipelineStage::kActivate])
     return;
+
   std::unique_ptr<CompositorFrameReporter> submitted_reporter =
       std::move(reporters_[PipelineStage::kActivate]);
   submitted_reporter->StartStage(
-      CompositorFrameReporter::StageType::
-          kSubmitCompositorFrameToPresentationCompositorFrame,
-      Now());
+      StageType::kSubmitCompositorFrameToPresentationCompositorFrame, Now());
   submitted_compositor_frames_.emplace_back(frame_token,
                                             std::move(submitted_reporter));
 }
 
+void CompositorFrameReportingController::OnFinishImplFrame() {
+  if (reporters_[PipelineStage::kBeginImplFrame]) {
+    reporters_[PipelineStage::kBeginImplFrame]->OnFinishImplFrame(Now());
+  } else if (reporters_[PipelineStage::kBeginMainFrame]) {
+    auto& begin_main_reporter = reporters_[PipelineStage::kBeginMainFrame];
+    begin_main_reporter->OnFinishImplFrame(Now());
+
+    // If the main-frame was aborted (e.g. there was no visible update), then
+    // advance to activate stage if the compositor has already made changes to
+    // the active tree (i.e. if impl-frame has finished).
+    if (begin_main_reporter->did_abort_main_frame()) {
+      begin_main_reporter->StartStage(
+          StageType::kEndActivateToSubmitCompositorFrame, Now());
+      AdvanceReporterStage(PipelineStage::kBeginMainFrame,
+                           PipelineStage::kActivate);
+    }
+  }
+}
+
 void CompositorFrameReportingController::DidPresentCompositorFrame(
     uint32_t frame_token,
     const viz::FrameTimingDetails& details) {
diff --git a/cc/metrics/compositor_frame_reporting_controller.h b/cc/metrics/compositor_frame_reporting_controller.h
index 997d26b..80254c1d 100644
--- a/cc/metrics/compositor_frame_reporting_controller.h
+++ b/cc/metrics/compositor_frame_reporting_controller.h
@@ -57,6 +57,7 @@
   virtual void WillActivate();
   virtual void DidActivate();
   virtual void DidSubmitCompositorFrame(uint32_t frame_token);
+  virtual void OnFinishImplFrame();
   virtual void DidPresentCompositorFrame(
       uint32_t frame_token,
       const viz::FrameTimingDetails& details);
diff --git a/cc/metrics/compositor_timing_history.cc b/cc/metrics/compositor_timing_history.cc
index 9e7b2ac..930a089 100644
--- a/cc/metrics/compositor_timing_history.cc
+++ b/cc/metrics/compositor_timing_history.cc
@@ -721,6 +721,8 @@
 void CompositorTimingHistory::WillFinishImplFrame(bool needs_redraw) {
   if (!needs_redraw)
     SetCompositorDrawingContinuously(false);
+
+  compositor_frame_reporting_controller_->OnFinishImplFrame();
 }
 
 void CompositorTimingHistory::BeginImplFrameNotExpectedSoon() {
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index 3245505e..5ec8b26 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -701,8 +701,6 @@
         tile->use_picture_analysis() && kUseColorEstimator) {
       // We analyze for solid color here, to decide to continue
       // or drop the tile for scheduling and raster.
-      // TODO(sohanjg): Check if we could use a shared analysis
-      // canvas which is reset between tiles.
       tile->set_solid_color_analysis_performed(true);
       SkColor color = SK_ColorTRANSPARENT;
       bool is_solid_color =
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 7ef7f55..799a127 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6652,6 +6652,19 @@
         Download
       </message>
 
+    <!-- Different device types using in Sharing. -->
+      <message name="IDS_BROWSER_SHARING_DEVICE_TYPE_COMPUTER" desc = "The label for a device of type computer.">
+        Computer
+      </message>
+      <message name="IDS_BROWSER_SHARING_DEVICE_TYPE_DEVICE" desc = "The label for a generic device.">
+        Device
+      </message>
+      <message name="IDS_BROWSER_SHARING_DEVICE_TYPE_PHONE" desc = "The label for a device of type phone.">
+        Phone
+      </message>
+      <message name="IDS_BROWSER_SHARING_DEVICE_TYPE_TABLET" desc = "The label for a device of type tablet.">
+        Tablet
+      </message>
 
       <!-- Sharing features. -->
       <if expr="not use_titlecase">
diff --git a/chrome/app/generated_resources_grd/IDS_BROWSER_SHARING_DEVICE_TYPE_COMPUTER.png.sha1 b/chrome/app/generated_resources_grd/IDS_BROWSER_SHARING_DEVICE_TYPE_COMPUTER.png.sha1
new file mode 100644
index 0000000..59c7d70a
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_BROWSER_SHARING_DEVICE_TYPE_COMPUTER.png.sha1
@@ -0,0 +1 @@
+e2f58aa03825c6decf2d008aabb2da8d33a4af78
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_BROWSER_SHARING_DEVICE_TYPE_DEVICE.png.sha1 b/chrome/app/generated_resources_grd/IDS_BROWSER_SHARING_DEVICE_TYPE_DEVICE.png.sha1
new file mode 100644
index 0000000..59c7d70a
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_BROWSER_SHARING_DEVICE_TYPE_DEVICE.png.sha1
@@ -0,0 +1 @@
+e2f58aa03825c6decf2d008aabb2da8d33a4af78
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_BROWSER_SHARING_DEVICE_TYPE_PHONE.png.sha1 b/chrome/app/generated_resources_grd/IDS_BROWSER_SHARING_DEVICE_TYPE_PHONE.png.sha1
new file mode 100644
index 0000000..59c7d70a
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_BROWSER_SHARING_DEVICE_TYPE_PHONE.png.sha1
@@ -0,0 +1 @@
+e2f58aa03825c6decf2d008aabb2da8d33a4af78
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_BROWSER_SHARING_DEVICE_TYPE_TABLET.png.sha1 b/chrome/app/generated_resources_grd/IDS_BROWSER_SHARING_DEVICE_TYPE_TABLET.png.sha1
new file mode 100644
index 0000000..59c7d70a
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_BROWSER_SHARING_DEVICE_TYPE_TABLET.png.sha1
@@ -0,0 +1 @@
+e2f58aa03825c6decf2d008aabb2da8d33a4af78
\ No newline at end of file
diff --git a/chrome/app/profiles_strings.grdp b/chrome/app/profiles_strings.grdp
index a25a35d9..5561629 100644
--- a/chrome/app/profiles_strings.grdp
+++ b/chrome/app/profiles_strings.grdp
@@ -108,6 +108,12 @@
   <message name="IDS_PROFILES_EXIT_GUEST" desc="Button in the avatar menu bubble view for exiting the active guest session.">
     Exit Guest
   </message>
+  <message name="IDS_PROFILES_CLOSE_X_WINDOWS_BUTTON" desc="Button in the profile menu to close all windows of the current profile. This is not used for zero windows.">
+    {0, plural,
+    =1 {Close # window}
+    other {Close # windows}
+    }
+  </message>
   <message name="IDS_PROFILES_SIGNIN_PROMO" desc="Text describing the benefits of signing in.">
     Sign in to get your bookmarks, history, passwords, and other settings on all your devices.
   </message>
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn
index e4919e55..3a6f479 100644
--- a/chrome/app/vector_icons/BUILD.gn
+++ b/chrome/app/vector_icons/BUILD.gn
@@ -91,9 +91,9 @@
     "save_original_file.icon",
     "security.icon",
     "send_tab_to_self.icon",
-    "shield_dot.icon",
-    "shield_off.icon",
-    "shield_outline.icon",
+    "eye_crossed.icon",
+    "eye_crossed_dot.icon",
+    "eye.icon",
     "sensors.icon",
     "signin_button_drop_down_arrow.icon",
     "sign_out.icon",
diff --git a/chrome/app/vector_icons/eye.icon b/chrome/app/vector_icons/eye.icon
new file mode 100644
index 0000000..65c02ad
--- /dev/null
+++ b/chrome/app/vector_icons/eye.icon
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 16,
+MOVE_TO, 8, 5.67f,
+CUBIC_TO, 7.47f, 5.67f, 6.96f, 5.88f, 6.59f, 6.25f,
+CUBIC_TO, 6.21f, 6.63f, 6, 7.14f, 6, 7.67f,
+CUBIC_TO, 6, 8.2f, 6.21f, 8.71f, 6.59f, 9.08f,
+CUBIC_TO, 6.96f, 9.46f, 7.47f, 9.67f, 8, 9.67f,
+CUBIC_TO, 8.53f, 9.67f, 9.04f, 9.46f, 9.41f, 9.08f,
+CUBIC_TO, 9.79f, 8.71f, 10, 8.2f, 10, 7.67f,
+CUBIC_TO, 10, 7.14f, 9.79f, 6.63f, 9.41f, 6.25f,
+CUBIC_TO, 9.04f, 5.88f, 8.53f, 5.67f, 8, 5.67f,
+CLOSE,
+MOVE_TO, 8, 11,
+CUBIC_TO, 7.12f, 11, 6.27f, 10.65f, 5.64f, 10.02f,
+CUBIC_TO, 5.02f, 9.4f, 4.67f, 8.55f, 4.67f, 7.67f,
+CUBIC_TO, 4.67f, 6.78f, 5.02f, 5.93f, 5.64f, 5.31f,
+CUBIC_TO, 6.27f, 4.68f, 7.12f, 4.33f, 8, 4.33f,
+CUBIC_TO, 8.88f, 4.33f, 9.73f, 4.68f, 10.36f, 5.31f,
+CUBIC_TO, 10.98f, 5.93f, 11.33f, 6.78f, 11.33f, 7.67f,
+CUBIC_TO, 11.33f, 8.55f, 10.98f, 9.4f, 10.36f, 10.02f,
+CUBIC_TO, 9.73f, 10.65f, 8.88f, 11, 8, 11,
+V_LINE_TO, 11,
+CLOSE,
+MOVE_TO, 8, 2.67f,
+CUBIC_TO, 4.67f, 2.67f, 1.82f, 4.74f, 0.67f, 7.67f,
+CUBIC_TO, 1.82f, 10.59f, 4.67f, 12.67f, 8, 12.67f,
+CUBIC_TO, 11.33f, 12.67f, 14.18f, 10.59f, 15.33f, 7.67f,
+CUBIC_TO, 14.18f, 4.74f, 11.33f, 2.67f, 8, 2.67f,
+CLOSE
diff --git a/chrome/app/vector_icons/eye_crossed.icon b/chrome/app/vector_icons/eye_crossed.icon
new file mode 100644
index 0000000..9103ee9
--- /dev/null
+++ b/chrome/app/vector_icons/eye_crossed.icon
@@ -0,0 +1,38 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 16,
+MOVE_TO, 2.53f, 1.47f,
+LINE_TO, 14.53f, 13.47f,
+LINE_TO, 13.47f, 14.53f,
+LINE_TO, 11.01f, 12.07f,
+CUBIC_TO, 10.08f, 12.45f, 9.07f, 12.67f, 8, 12.67f,
+CUBIC_TO, 4.67f, 12.67f, 1.82f, 10.59f, 0.67f, 7.67f,
+CUBIC_TO, 1.2f, 6.32f, 2.09f, 5.15f, 3.22f, 4.28f,
+LINE_TO, 1.47f, 2.53f,
+LINE_TO, 2.53f, 1.47f,
+CLOSE,
+MOVE_TO, 5.05f, 6.11f,
+CUBIC_TO, 4.8f, 6.59f, 4.67f, 7.12f, 4.67f, 7.67f,
+CUBIC_TO, 4.67f, 8.55f, 5.02f, 9.4f, 5.64f, 10.02f,
+CUBIC_TO, 6.27f, 10.65f, 7.12f, 11, 8, 11,
+CUBIC_TO, 8.55f, 11, 9.08f, 10.87f, 9.55f, 10.62f,
+LINE_TO, 8.53f, 9.59f,
+CUBIC_TO, 8.36f, 9.64f, 8.18f, 9.67f, 8, 9.67f,
+CUBIC_TO, 7.47f, 9.67f, 6.96f, 9.46f, 6.59f, 9.08f,
+CUBIC_TO, 6.21f, 8.71f, 6, 8.2f, 6, 7.67f,
+CUBIC_TO, 6, 7.48f, 6.02f, 7.31f, 6.07f, 7.13f,
+LINE_TO, 5.05f, 6.11f,
+CLOSE,
+MOVE_TO, 7.44f, 4.38f,
+LINE_TO, 5.99f, 2.93f,
+CUBIC_TO, 6.63f, 2.76f, 7.3f, 2.67f, 8, 2.67f,
+CUBIC_TO, 11.33f, 2.67f, 14.18f, 4.74f, 15.33f, 7.67f,
+CUBIC_TO, 14.92f, 8.72f, 14.29f, 9.66f, 13.49f, 10.43f,
+LINE_TO, 11.29f, 8.23f,
+CUBIC_TO, 11.32f, 8.04f, 11.33f, 7.86f, 11.33f, 7.67f,
+CUBIC_TO, 11.33f, 6.78f, 10.98f, 5.93f, 10.36f, 5.31f,
+CUBIC_TO, 9.73f, 4.68f, 8.88f, 4.33f, 8, 4.33f,
+CUBIC_TO, 7.81f, 4.33f, 7.62f, 4.35f, 7.44f, 4.38f,
+CLOSE
diff --git a/chrome/app/vector_icons/eye_crossed_dot.icon b/chrome/app/vector_icons/eye_crossed_dot.icon
new file mode 100644
index 0000000..e8d8b06
--- /dev/null
+++ b/chrome/app/vector_icons/eye_crossed_dot.icon
@@ -0,0 +1,49 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 16,
+MOVE_TO, 13.93f, 5.37f,
+CUBIC_TO, 13.55f, 5.55f, 13.12f, 5.65f, 12.67f, 5.65f,
+CUBIC_TO, 11.08f, 5.65f, 9.78f, 4.41f, 9.67f, 2.85f,
+CUBIC_TO, 9.13f, 2.73f, 8.57f, 2.67f, 8, 2.67f,
+CUBIC_TO, 7.3f, 2.67f, 6.63f, 2.76f, 5.99f, 2.93f,
+LINE_TO, 7.44f, 4.38f,
+CUBIC_TO, 7.62f, 4.35f, 7.81f, 4.34f, 8, 4.34f,
+CUBIC_TO, 8.88f, 4.34f, 9.73f, 4.69f, 10.36f, 5.31f,
+CUBIC_TO, 10.98f, 5.94f, 11.33f, 6.79f, 11.33f, 7.67f,
+CUBIC_TO, 11.33f, 7.86f, 11.32f, 8.05f, 11.29f, 8.23f,
+LINE_TO, 13.49f, 10.44f,
+CUBIC_TO, 14.29f, 9.66f, 14.92f, 8.72f, 15.33f, 7.67f,
+CUBIC_TO, 15, 6.82f, 14.52f, 6.05f, 13.93f, 5.37f,
+CLOSE,
+MOVE_TO, 2.53f, 1.47f,
+LINE_TO, 1.47f, 2.53f,
+LINE_TO, 3.22f, 4.29f,
+CUBIC_TO, 2.09f, 5.15f, 1.2f, 6.32f, 0.67f, 7.67f,
+CUBIC_TO, 1.82f, 10.6f, 4.67f, 12.67f, 8, 12.67f,
+CUBIC_TO, 9.07f, 12.67f, 10.08f, 12.46f, 11.01f, 12.07f,
+LINE_TO, 13.47f, 14.53f,
+LINE_TO, 14.53f, 13.47f,
+LINE_TO, 2.53f, 1.47f,
+CLOSE,
+MOVE_TO, 4.67f, 7.67f,
+CUBIC_TO, 4.67f, 7.12f, 4.8f, 6.59f, 5.05f, 6.12f,
+LINE_TO, 6.07f, 7.14f,
+CUBIC_TO, 6.02f, 7.31f, 6, 7.49f, 6, 7.67f,
+CUBIC_TO, 6, 8.2f, 6.21f, 8.71f, 6.59f, 9.08f,
+CUBIC_TO, 6.96f, 9.46f, 7.47f, 9.67f, 8, 9.67f,
+CUBIC_TO, 8.18f, 9.67f, 8.36f, 9.65f, 8.53f, 9.6f,
+LINE_TO, 9.55f, 10.62f,
+CUBIC_TO, 9.08f, 10.87f, 8.55f, 11, 8, 11,
+CUBIC_TO, 7.12f, 11, 6.27f, 10.65f, 5.64f, 10.03f,
+CUBIC_TO, 5.02f, 9.4f, 4.67f, 8.55f, 4.67f, 7.67f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x1A, 0x73, 0xE8,
+MOVE_TO, 12.67f, 4.65f,
+CUBIC_TO, 13.77f, 4.65f, 14.67f, 3.75f, 14.67f, 2.65f,
+CUBIC_TO, 14.67f, 1.55f, 13.77f, 0.65f, 12.67f, 0.65f,
+CUBIC_TO, 11.56f, 0.65f, 10.67f, 1.55f, 10.67f, 2.65f,
+CUBIC_TO, 10.67f, 3.75f, 11.56f, 4.65f, 12.67f, 4.65f,
+CLOSE
diff --git a/chrome/app/vector_icons/shield_dot.icon b/chrome/app/vector_icons/shield_dot.icon
deleted file mode 100644
index 370c58f..0000000
--- a/chrome/app/vector_icons/shield_dot.icon
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 16,
-MOVE_TO, 14, 6.24f,
-LINE_TO, 14, 7.36f,
-CUBIC_TO, 14, 10.9f, 11.44f, 14.2f, 8, 15,
-CUBIC_TO, 4.56f, 14.2f, 2, 10.9f, 2, 7.36f,
-LINE_TO, 2, 3.55f,
-LINE_TO, 8, 1,
-LINE_TO, 9.94f, 1.82f,
-CUBIC_TO, 9.62f, 2.12f, 9.37f, 2.49f, 9.21f, 2.91f,
-LINE_TO, 8, 2.39f,
-LINE_TO, 3.33f, 4.37f,
-LINE_TO, 3.33f, 7.36f,
-CUBIC_TO, 3.33f, 10.24f, 5.32f, 12.89f, 8, 13.68f,
-CUBIC_TO, 10.68f, 12.89f, 12.67f, 10.24f, 12.67f, 7.36f,
-LINE_TO, 12.67f, 6.93f,
-CUBIC_TO, 13.17f, 6.81f, 13.63f, 6.57f, 14, 6.24f,
-CLOSE,
-NEW_PATH,
-PATH_COLOR_ARGB, 0xFF, 0x1A, 0x73, 0xE8,
-MOVE_TO, 12, 6,
-CUBIC_TO, 10.9f, 6, 10, 5.1f, 10, 4,
-CUBIC_TO, 10, 2.9f, 10.9f, 2, 12, 2,
-CUBIC_TO, 13.1f, 2, 14, 2.9f, 14, 4,
-CUBIC_TO, 14, 5.1f, 13.1f, 6, 12, 6,
-CLOSE
diff --git a/chrome/app/vector_icons/shield_off.icon b/chrome/app/vector_icons/shield_off.icon
deleted file mode 100644
index 68b539a..0000000
--- a/chrome/app/vector_icons/shield_off.icon
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 16,
-MOVE_TO, 11.51f, 13.07f,
-CUBIC_TO, 10.54f, 14, 9.33f, 14.69f, 8, 15,
-CUBIC_TO, 4.56f, 14.2f, 2, 10.9f, 2, 7.36f,
-LINE_TO, 2, 3.56f,
-LINE_TO, 1.1f, 2.66f,
-LINE_TO, 2.16f, 1.6f,
-LINE_TO, 14.18f, 13.62f,
-LINE_TO, 13.12f, 14.68f,
-LINE_TO, 11.51f, 13.07f,
-CLOSE,
-MOVE_TO, 3.33f, 4.89f,
-LINE_TO, 3.33f, 7.36f,
-CUBIC_TO, 3.33f, 10.24f, 5.32f, 12.89f, 8, 13.68f,
-CUBIC_TO, 8.98f, 13.39f, 9.86f, 12.86f, 10.59f, 12.15f,
-LINE_TO, 3.33f, 4.89f,
-CLOSE,
-MOVE_TO, 13.29f, 10.57f,
-LINE_TO, 12.28f, 9.56f,
-CUBIC_TO, 12.53f, 8.86f, 12.67f, 8.12f, 12.67f, 7.36f,
-LINE_TO, 12.67f, 4.37f,
-LINE_TO, 8, 2.39f,
-LINE_TO, 5.97f, 3.25f,
-LINE_TO, 5, 2.27f,
-LINE_TO, 8, 1,
-LINE_TO, 14, 3.55f,
-LINE_TO, 14, 7.36f,
-CUBIC_TO, 14, 8.48f, 13.75f, 9.57f, 13.29f, 10.57f,
-CLOSE
diff --git a/chrome/app/vector_icons/shield_outline.icon b/chrome/app/vector_icons/shield_outline.icon
deleted file mode 100644
index 1fa1ab3..0000000
--- a/chrome/app/vector_icons/shield_outline.icon
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 16,
-MOVE_TO, 8, 0.67f,
-LINE_TO, 2, 3.33f,
-R_V_LINE_TO, 4,
-R_CUBIC_TO, 0, 3.7f, 2.56f, 7.16f, 6, 8,
-R_CUBIC_TO, 3.44f, -0.84f, 6, -4.3f, 6, -8,
-R_V_LINE_TO, -4,
-LINE_TO, 8, 0.67f,
-CLOSE,
-R_MOVE_TO, 4.67f, 6.67f,
-R_CUBIC_TO, 0, 3.01f, -1.99f, 5.79f, -4.67f, 6.62f,
-R_CUBIC_TO, -2.68f, -0.83f, -4.67f, -3.61f, -4.67f, -6.62f,
-V_LINE_TO, 4.2f,
-LINE_TO, 8, 2.13f,
-LINE_TO, 12.67f, 4.2f,
-R_V_LINE_TO, 3.13f,
-CLOSE
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 22ba3fed..fd68a5ee 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2934,6 +2934,8 @@
       "apps/app_service/app_service_proxy_factory.h",
       "apps/app_service/dip_px_util.cc",
       "apps/app_service/dip_px_util.h",
+      "apps/app_service/uninstall_dialog.cc",
+      "apps/app_service/uninstall_dialog.h",
       "apps/intent_helper/apps_navigation_throttle.cc",
       "apps/intent_helper/apps_navigation_throttle.h",
       "apps/intent_helper/apps_navigation_types.cc",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 377660b..c7689ad 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -417,7 +417,6 @@
   "+third_party/blink/public/platform/web_mouse_event.h",
   "+third_party/blink/public/platform/web_mouse_wheel_event.h",
   "+third_party/blink/public/platform/web_touch_event.h",
-  "+third_party/blink/public/platform/web_security_style.h",
   "+third_party/blink/public/platform/web_sudden_termination_disabler_type.h",
   "+third_party/blink/public/public_buildflags.h",
   "+third_party/blink/public/web/web_context_menu_data.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 972a9a0..ae1545374 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2989,11 +2989,6 @@
      flag_descriptions::kDisableKeepaliveFetchDescription, kOsAll,
      FEATURE_VALUE_TYPE(network::features::kDisableKeepaliveFetch)},
 
-    {"enable-resource-load-scheduler",
-     flag_descriptions::kResourceLoadSchedulerName,
-     flag_descriptions::kResourceLoadSchedulerDescription, kOsAll,
-     FEATURE_VALUE_TYPE(features::kResourceLoadScheduler)},
-
     {"prefetch-privacy-changes", flag_descriptions::kPrefetchPrivacyChangesName,
      flag_descriptions::kPrefetchPrivacyChangesDescription, kOsAll,
      FEATURE_VALUE_TYPE(blink::features::kPrefetchPrivacyChanges)},
@@ -4264,6 +4259,12 @@
      FEATURE_VALUE_TYPE(chromeos::features::kSplitSettings)},
 #endif  // defined(OS_CHROMEOS)
 
+    {"privacy-settings-redesign",
+     flag_descriptions::kPrivacySettingsRedesignName,
+     flag_descriptions::kPrivacySettingsRedesignDescription,
+     kOsWin | kOsMac | kOsLinux,
+     FEATURE_VALUE_TYPE(features::kPrivacySettingsRedesign)},
+
 #if defined(OS_CHROMEOS)
     {"gesture-properties-dbus-service",
      flag_descriptions::kEnableGesturePropertiesDBusServiceName,
diff --git a/chrome/browser/android/profiles/profile_downloader_android.cc b/chrome/browser/android/profiles/profile_downloader_android.cc
index 4bd2bcd..5da6417 100644
--- a/chrome/browser/android/profiles/profile_downloader_android.cc
+++ b/chrome/browser/android/profiles/profile_downloader_android.cc
@@ -33,7 +33,7 @@
 class AccountInfoRetriever : public ProfileDownloaderDelegate {
  public:
   AccountInfoRetriever(Profile* profile,
-                       const std::string& account_id,
+                       const CoreAccountId& account_id,
                        const std::string& email,
                        const int desired_image_side_pixels,
                        bool is_pre_signin)
@@ -112,7 +112,7 @@
   Profile* profile_;
 
   // The account ID and email address of account to be loaded.
-  const std::string account_id_;
+  const CoreAccountId account_id_;
   const std::string email_;
 
   // Desired side length of the profile image (in pixels).
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc
index fd742d82..8a5bafa 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.cc
+++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -414,7 +414,7 @@
     new_contents.release();
 }
 
-blink::WebSecurityStyle TabWebContentsDelegateAndroid::GetSecurityStyle(
+blink::SecurityStyle TabWebContentsDelegateAndroid::GetSecurityStyle(
     WebContents* web_contents,
     content::SecurityStyleExplanations* security_style_explanations) {
   SecurityStateTabHelper* helper =
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.h b/chrome/browser/android/tab_web_contents_delegate_android.h
index 75028fd..0ad83c1 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.h
+++ b/chrome/browser/android/tab_web_contents_delegate_android.h
@@ -98,7 +98,7 @@
                       const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
-  blink::WebSecurityStyle GetSecurityStyle(
+  blink::SecurityStyle GetSecurityStyle(
       content::WebContents* web_contents,
       content::SecurityStyleExplanations* security_style_explanations) override;
   void OnDidBlockNavigation(content::WebContents* web_contents,
diff --git a/chrome/browser/apps/app_service/app_service_proxy.cc b/chrome/browser/apps/app_service/app_service_proxy.cc
index ab708b6..95bdac3 100644
--- a/chrome/browser/apps/app_service/app_service_proxy.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/apps/app_service/app_icon_source.h"
 #include "chrome/browser/apps/app_service/app_service_metrics.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/apps/app_service/uninstall_dialog.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/services/app_service/app_service_impl.h"
 #include "chrome/services/app_service/public/cpp/intent_util.h"
@@ -211,11 +212,27 @@
 void AppServiceProxy::Uninstall(const std::string& app_id) {
   if (app_service_.is_connected()) {
     cache_.ForOneApp(app_id, [this](const apps::AppUpdate& update) {
-      app_service_->Uninstall(update.AppType(), update.AppId());
+      app_service_->PromptUninstall(update.AppType(), update.AppId());
     });
   }
 }
 
+void AppServiceProxy::OnUninstallDialogClosed(
+    apps::mojom::AppType app_type,
+    const std::string& app_id,
+    bool uninstall,
+    bool clear_site_data,
+    bool report_abuse,
+    UninstallDialog* uninstall_dialog) {
+  if (uninstall)
+    app_service_->Uninstall(app_type, app_id, clear_site_data, report_abuse);
+
+  DCHECK(uninstall_dialog);
+  auto it = uninstall_dialogs_.find(uninstall_dialog);
+  DCHECK(it != uninstall_dialogs_.end());
+  uninstall_dialogs_.erase(it);
+}
+
 void AppServiceProxy::OpenNativeSettings(const std::string& app_id) {
   if (app_service_.is_connected()) {
     cache_.ForOneApp(app_id, [this](const apps::AppUpdate& update) {
@@ -289,6 +306,8 @@
 }
 
 void AppServiceProxy::Shutdown() {
+  uninstall_dialogs_.clear();
+
 #if defined(OS_CHROMEOS)
   if (app_service_.is_connected()) {
     extension_apps_->Shutdown();
diff --git a/chrome/browser/apps/app_service/app_service_proxy.h b/chrome/browser/apps/app_service/app_service_proxy.h
index 7719589e..8392ad2 100644
--- a/chrome/browser/apps/app_service/app_service_proxy.h
+++ b/chrome/browser/apps/app_service/app_service_proxy.h
@@ -6,9 +6,12 @@
 #define CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_H_
 
 #include <memory>
+#include <set>
 
+#include "base/containers/unique_ptr_adapters.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/apps/app_service/uninstall_dialog.h"
 #include "chrome/services/app_service/public/cpp/app_registry_cache.h"
 #include "chrome/services/app_service/public/cpp/icon_cache.h"
 #include "chrome/services/app_service/public/cpp/icon_coalescer.h"
@@ -75,6 +78,12 @@
   void SetPermission(const std::string& app_id,
                      apps::mojom::PermissionPtr permission);
   void Uninstall(const std::string& app_id);
+  void OnUninstallDialogClosed(apps::mojom::AppType app_type,
+                               const std::string& app_id,
+                               bool uninstall,
+                               bool clear_site_data,
+                               bool report_abuse,
+                               UninstallDialog* uninstall_dialog);
   void OpenNativeSettings(const std::string& app_id);
 
   void FlushMojoCallsForTesting();
@@ -187,6 +196,10 @@
 
   Profile* profile_;
 
+  using UninstallDialogs = std::set<std::unique_ptr<apps::UninstallDialog>,
+                                    base::UniquePtrComparator>;
+  UninstallDialogs uninstall_dialogs_;
+
   base::WeakPtrFactory<AppServiceProxy> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(AppServiceProxy);
diff --git a/chrome/browser/apps/app_service/arc_apps.cc b/chrome/browser/apps/app_service/arc_apps.cc
index 48c852d..9a80e6d2 100644
--- a/chrome/browser/apps/app_service/arc_apps.cc
+++ b/chrome/browser/apps/app_service/arc_apps.cc
@@ -396,13 +396,19 @@
   }
 }
 
-void ArcApps::Uninstall(const std::string& app_id) {
+void ArcApps::PromptUninstall(const std::string& app_id) {
   if (!profile_) {
     return;
   }
   arc::ShowArcAppUninstallDialog(profile_, nullptr /* controller */, app_id);
 }
 
+void ArcApps::Uninstall(const std::string& app_id,
+                        bool clear_site_data,
+                        bool report_abuse) {
+  arc::UninstallArcApp(app_id, profile_);
+}
+
 void ArcApps::OpenNativeSettings(const std::string& app_id) {
   ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_);
   if (!prefs) {
diff --git a/chrome/browser/apps/app_service/arc_apps.h b/chrome/browser/apps/app_service/arc_apps.h
index 11e263c7..a38a614 100644
--- a/chrome/browser/apps/app_service/arc_apps.h
+++ b/chrome/browser/apps/app_service/arc_apps.h
@@ -73,7 +73,10 @@
                            int64_t display_id) override;
   void SetPermission(const std::string& app_id,
                      apps::mojom::PermissionPtr permission) override;
-  void Uninstall(const std::string& app_id) override;
+  void PromptUninstall(const std::string& app_id) override;
+  void Uninstall(const std::string& app_id,
+                 bool clear_site_data,
+                 bool report_abuse) override;
   void OpenNativeSettings(const std::string& app_id) override;
 
   // ArcAppListPrefs::Observer overrides.
diff --git a/chrome/browser/apps/app_service/built_in_chromeos_apps.cc b/chrome/browser/apps/app_service/built_in_chromeos_apps.cc
index 18cf83c..7a9b028 100644
--- a/chrome/browser/apps/app_service/built_in_chromeos_apps.cc
+++ b/chrome/browser/apps/app_service/built_in_chromeos_apps.cc
@@ -174,7 +174,15 @@
   NOTIMPLEMENTED();
 }
 
-void BuiltInChromeOsApps::Uninstall(const std::string& app_id) {
+void BuiltInChromeOsApps::PromptUninstall(const std::string& app_id) {
+  constexpr bool kClearSiteData = false;
+  constexpr bool kReportAbuse = false;
+  Uninstall(app_id, kClearSiteData, kReportAbuse);
+}
+
+void BuiltInChromeOsApps::Uninstall(const std::string& app_id,
+                                    bool clear_site_data,
+                                    bool report_abuse) {
   LOG(ERROR) << "Uninstall failed, could not remove built-in app with id "
              << app_id;
 }
diff --git a/chrome/browser/apps/app_service/built_in_chromeos_apps.h b/chrome/browser/apps/app_service/built_in_chromeos_apps.h
index e2dc651..c150062 100644
--- a/chrome/browser/apps/app_service/built_in_chromeos_apps.h
+++ b/chrome/browser/apps/app_service/built_in_chromeos_apps.h
@@ -52,7 +52,10 @@
                            int64_t display_id) override;
   void SetPermission(const std::string& app_id,
                      apps::mojom::PermissionPtr permission) override;
-  void Uninstall(const std::string& app_id) override;
+  void PromptUninstall(const std::string& app_id) override;
+  void Uninstall(const std::string& app_id,
+                 bool clear_site_data,
+                 bool report_abuse) override;
   void OpenNativeSettings(const std::string& app_id) override;
 
   mojo::Receiver<apps::mojom::Publisher> receiver_{this};
diff --git a/chrome/browser/apps/app_service/crostini_apps.cc b/chrome/browser/apps/app_service/crostini_apps.cc
index b551276..0e2635e 100644
--- a/chrome/browser/apps/app_service/crostini_apps.cc
+++ b/chrome/browser/apps/app_service/crostini_apps.cc
@@ -152,7 +152,13 @@
   NOTIMPLEMENTED();
 }
 
-void CrostiniApps::Uninstall(const std::string& app_id) {
+void CrostiniApps::PromptUninstall(const std::string& app_id) {
+  NOTIMPLEMENTED();
+}
+
+void CrostiniApps::Uninstall(const std::string& app_id,
+                             bool clear_site_data,
+                             bool report_abuse) {
   NOTIMPLEMENTED();
 }
 
diff --git a/chrome/browser/apps/app_service/crostini_apps.h b/chrome/browser/apps/app_service/crostini_apps.h
index fd2dd4ec..7559432 100644
--- a/chrome/browser/apps/app_service/crostini_apps.h
+++ b/chrome/browser/apps/app_service/crostini_apps.h
@@ -70,7 +70,10 @@
                            int64_t display_id) override;
   void SetPermission(const std::string& app_id,
                      apps::mojom::PermissionPtr permission) override;
-  void Uninstall(const std::string& app_id) override;
+  void PromptUninstall(const std::string& app_id) override;
+  void Uninstall(const std::string& app_id,
+                 bool clear_site_data,
+                 bool report_abuse) override;
   void OpenNativeSettings(const std::string& app_id) override;
 
   // CrostiniRegistryService::Observer overrides.
diff --git a/chrome/browser/apps/app_service/extension_apps.cc b/chrome/browser/apps/app_service/extension_apps.cc
index 95f7d6d..2cdfe80a 100644
--- a/chrome/browser/apps/app_service/extension_apps.cc
+++ b/chrome/browser/apps/app_service/extension_apps.cc
@@ -43,8 +43,10 @@
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
 #include "components/content_settings/core/common/content_settings_types.h"
+#include "content/public/browser/clear_site_data_utils.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/extension_urls.h"
 #include "extensions/common/switches.h"
 #include "url/url_constants.h"
 
@@ -403,7 +405,7 @@
       permission_value);
 }
 
-void ExtensionApps::Uninstall(const std::string& app_id) {
+void ExtensionApps::PromptUninstall(const std::string& app_id) {
   if (!profile_) {
     return;
   }
@@ -414,6 +416,60 @@
   uninstaller->Run();
 }
 
+void ExtensionApps::Uninstall(const std::string& app_id,
+                              bool clear_site_data,
+                              bool report_abuse) {
+  // TODO(crbug.com/1009248): We need to add the error code, which could be used
+  // by ExtensionFunction, ManagementUninstallFunctionBase on the callback
+  // OnExtensionUninstallDialogClosed
+  const extensions::Extension* extension =
+      extensions::ExtensionRegistry::Get(profile_)->GetInstalledExtension(
+          app_id);
+  if (!extension) {
+    return;
+  }
+
+  base::string16 error;
+  extensions::ExtensionSystem::Get(profile_)
+      ->extension_service()
+      ->UninstallExtension(
+          app_id, extensions::UninstallReason::UNINSTALL_REASON_USER_INITIATED,
+          &error);
+
+  if (!clear_site_data) {
+    return;
+  }
+
+  if (extension->from_bookmark()) {
+    constexpr bool kClearCookies = true;
+    constexpr bool kClearStorage = true;
+    constexpr bool kClearCache = true;
+    constexpr bool kAvoidClosingConnections = false;
+    content::ClearSiteData(
+        base::BindRepeating(
+            [](content::BrowserContext* browser_context) {
+              return browser_context;
+            },
+            base::Unretained(profile_)),
+        url::Origin::Create(
+            extensions::AppLaunchInfo::GetFullLaunchURL(extension)),
+        kClearCookies, kClearStorage, kClearCache, kAvoidClosingConnections,
+        base::DoNothing());
+  } else {
+    // If the extension specifies a custom uninstall page via
+    // chrome.runtime.setUninstallURL, then at uninstallation its uninstall
+    // page opens. To ensure that the CWS Report Abuse page is the active
+    // tab at uninstallation, navigates to the url to report abuse.
+    constexpr char kReferrerId[] = "chrome-remove-extension-dialog";
+    NavigateParams params(
+        profile_,
+        extension_urls::GetWebstoreReportAbuseUrl(app_id, kReferrerId),
+        ui::PAGE_TRANSITION_LINK);
+    params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+    Navigate(&params);
+  }
+}
+
 void ExtensionApps::OpenNativeSettings(const std::string& app_id) {
   if (!profile_) {
     return;
diff --git a/chrome/browser/apps/app_service/extension_apps.h b/chrome/browser/apps/app_service/extension_apps.h
index 25391656..74f6717 100644
--- a/chrome/browser/apps/app_service/extension_apps.h
+++ b/chrome/browser/apps/app_service/extension_apps.h
@@ -84,7 +84,10 @@
                            int64_t display_id) override;
   void SetPermission(const std::string& app_id,
                      apps::mojom::PermissionPtr permission) override;
-  void Uninstall(const std::string& app_id) override;
+  void PromptUninstall(const std::string& app_id) override;
+  void Uninstall(const std::string& app_id,
+                 bool clear_site_data,
+                 bool report_abuse) override;
   void OpenNativeSettings(const std::string& app_id) override;
 
   // content_settings::Observer overrides.
diff --git a/chrome/browser/apps/app_service/uninstall_dialog.cc b/chrome/browser/apps/app_service/uninstall_dialog.cc
new file mode 100644
index 0000000..fbe0bbe
--- /dev/null
+++ b/chrome/browser/apps/app_service/uninstall_dialog.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/apps/app_service/uninstall_dialog.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/services/app_service/public/cpp/icon_loader.h"
+
+namespace apps {
+
+UninstallDialog::UninstallDialog(Profile* profile,
+                                 apps::mojom::AppType app_type,
+                                 const std::string& app_id,
+                                 apps::mojom::IconKeyPtr icon_key,
+                                 apps::IconLoader* icon_loader,
+                                 UninstallCallback uninstall_callback)
+    : profile_(profile),
+      app_type_(app_type),
+      app_id_(app_id),
+      uninstall_callback_(std::move(uninstall_callback)) {
+  constexpr bool kAllowPlaceholderIcon = false;
+  icon_loader->LoadIconFromIconKey(
+      app_type, app_id, std::move(icon_key),
+      apps::mojom::IconCompression::kUncompressed, kSizeHintInDip,
+      kAllowPlaceholderIcon,
+      base::BindOnce(&UninstallDialog::OnLoadIcon,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+UninstallDialog::~UninstallDialog() = default;
+
+void UninstallDialog::OnDialogClosed(bool uninstall,
+                                     bool clear_site_data,
+                                     bool report_abuse) {
+  std::move(uninstall_callback_)
+      .Run(uninstall, clear_site_data, report_abuse, this);
+}
+
+void UninstallDialog::OnLoadIcon(apps::mojom::IconValuePtr icon_value) {
+  if (icon_value->icon_compression !=
+      apps::mojom::IconCompression::kUncompressed) {
+    return;
+  }
+
+  UiBase::Create(profile_, app_type_, app_id_, icon_value->uncompressed, this);
+}
+
+}  // namespace apps
diff --git a/chrome/browser/apps/app_service/uninstall_dialog.h b/chrome/browser/apps/app_service/uninstall_dialog.h
new file mode 100644
index 0000000..74f98fdbd
--- /dev/null
+++ b/chrome/browser/apps/app_service/uninstall_dialog.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_APPS_APP_SERVICE_UNINSTALL_DIALOG_H_
+#define CHROME_BROWSER_APPS_APP_SERVICE_UNINSTALL_DIALOG_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "chrome/services/app_service/public/mojom/types.mojom.h"
+
+class Profile;
+
+namespace gfx {
+class ImageSkia;
+}
+
+namespace apps {
+class IconLoader;
+class UninstallDialog;
+}  // namespace apps
+
+namespace apps {
+
+// Currently, app uninstallation on Chrome OS invokes a specific dialog per app
+// type, Chrome Apps / PWAs, ARC apps and Crostini. There are 3 separate views
+// for app uninstalling, which are subtly different from each other.
+//
+// This UninstallDialog combines the above three specific dialogs, and based on
+// different app type to generate different view. Once the user has confirmed,
+// the App Service calls the publisher to uninstall the app directly.
+//
+// TODO(crbug.com/1009248):
+// 1. Add an interface to the uninstall, like what is done by
+// extension_uninstall_dialog_->ConfirmUninstallByExtension
+// 2. Add RecordDialogCreation to the appropriate place as what is done by
+// extension_uninstall_dialog.
+// 3. Add UMA to the appropriate place as what is done by
+// extension_uninstall_dialog.
+class UninstallDialog {
+ public:
+  // The UiBase is the parent virtual class for the AppUninstallDialogView,
+  // which is located in
+  // chrome/browser/ui/view/apps/app_uninstall_dialog_view.h. The UiBase is also
+  // used to connect the UninstallDialog and AppUninstallDialogView, to transfer
+  // the icon image, and the callback function.
+  class UiBase {
+   public:
+    explicit UiBase(gfx::ImageSkia image, UninstallDialog* uninstall_dialog)
+        : image_(image), uninstall_dialog_(uninstall_dialog) {}
+
+    virtual ~UiBase() = default;
+
+    static void Create(Profile* profile,
+                       apps::mojom::AppType app_type,
+                       const std::string& app_id,
+                       gfx::ImageSkia image,
+                       UninstallDialog* uninstall_dialog);
+
+    gfx::ImageSkia image() const { return image_; }
+    UninstallDialog* uninstall_dialog() const { return uninstall_dialog_; }
+
+   private:
+    gfx::ImageSkia image_;
+    UninstallDialog* uninstall_dialog_;
+
+    DISALLOW_COPY_AND_ASSIGN(UiBase);
+  };
+
+  // Called when the dialog closes after the user has made a decision about
+  // whether to uninstall the app. If |clear_site_data| is true, site data will
+  // be removed after uninstalling the app. Only ever true for PWAs. If
+  // |report_abuse| is true, report abuse after uninstalling the app. Only ever
+  // true for Chrome Apps.
+  using UninstallCallback =
+      base::OnceCallback<void(bool uninstall,
+                              bool clear_site_data,
+                              bool report_rebuse,
+                              UninstallDialog* uninstall_dialog)>;
+
+  static constexpr int32_t kSizeHintInDip = 32;
+
+  UninstallDialog(Profile* profile,
+                  apps::mojom::AppType app_type,
+                  const std::string& app_id,
+                  apps::mojom::IconKeyPtr icon_key,
+                  IconLoader* icon_loader,
+                  UninstallCallback uninstall_callback);
+  ~UninstallDialog();
+
+  // Called when the uninstall dialog is closing to process uninstall or cancel
+  // the uninstall.
+  void OnDialogClosed(bool uninstall, bool clear_site_data, bool report_abuse);
+
+ private:
+  // Callback invoked when the icon is loaded.
+  void OnLoadIcon(apps::mojom::IconValuePtr icon_value);
+
+  Profile* profile_;
+  apps::mojom::AppType app_type_;
+  const std::string app_id_;
+  UninstallCallback uninstall_callback_;
+
+  base::WeakPtrFactory<UninstallDialog> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(UninstallDialog);
+};
+
+}  // namespace apps
+
+#endif  // CHROME_BROWSER_APPS_APP_SERVICE_UNINSTALL_DIALOG_H_
diff --git a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
index 0255e07..a579c87 100644
--- a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
+++ b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
@@ -29,6 +29,7 @@
 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
 #include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/extensions/launch_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_list.h"
diff --git a/chrome/browser/apps/app_shim/app_shim_listener_browsertest_mac.mm b/chrome/browser/apps/app_shim/app_shim_listener_browsertest_mac.mm
index 9f09c93f..1d63a74 100644
--- a/chrome/browser/apps/app_shim/app_shim_listener_browsertest_mac.mm
+++ b/chrome/browser/apps/app_shim/app_shim_listener_browsertest_mac.mm
@@ -18,6 +18,7 @@
 #include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h"
 #include "chrome/browser/apps/app_shim/test/app_shim_listener_test_api_mac.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm b/chrome/browser/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm
index bc70824d3..0a5b108de 100644
--- a/chrome/browser/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm
+++ b/chrome/browser/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm
@@ -18,6 +18,7 @@
 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
 #include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/lifetime/browser_shutdown.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
index 7780ff51..0081e5b 100644
--- a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
+++ b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/apps/app_shim/app_shim_termination_manager.h"
 #include "chrome/browser/apps/launch_service/launch_service.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/launch_util.h"
 #include "chrome/browser/profiles/avatar_menu.h"
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h
index 9a91407..b8ebffc 100644
--- a/chrome/browser/browser_process.h
+++ b/chrome/browser/browser_process.h
@@ -17,12 +17,13 @@
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
 #include "build/build_config.h"
-#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/common/buildflags.h"
 #include "media/media_buildflags.h"
 
 class BackgroundModeManager;
+class BrowserProcessPlatformPart;
 class DownloadRequestLimiter;
 class DownloadStatusUpdater;
 class GpuModeManager;
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 07b6117..d0cf8eca 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -35,6 +35,7 @@
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "chrome/browser/battery/battery_metrics.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_browser_main.h"
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/chrome_notification_types.h"
diff --git a/chrome/browser/browser_process_platform_part.h b/chrome/browser/browser_process_platform_part.h
index e87d007..5b215a1 100644
--- a/chrome/browser/browser_process_platform_part.h
+++ b/chrome/browser/browser_process_platform_part.h
@@ -18,7 +18,7 @@
 #include "chrome/browser/browser_process_platform_part_win.h"
 #else
 #include "chrome/browser/browser_process_platform_part_base.h"
-typedef BrowserProcessPlatformPartBase BrowserProcessPlatformPart;
+class BrowserProcessPlatformPart : public BrowserProcessPlatformPartBase {};
 #endif
 
 #endif  // CHROME_BROWSER_BROWSER_PROCESS_PLATFORM_PART_H_
diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm
index beb291f..53a4ad6 100644
--- a/chrome/browser/chrome_browser_main_mac.mm
+++ b/chrome/browser/chrome_browser_main_mac.mm
@@ -27,6 +27,7 @@
 #import "chrome/browser/app_controller_mac.h"
 #include "chrome/browser/apps/app_shim/app_shim_listener.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #import "chrome/browser/chrome_browser_application_mac.h"
 #include "chrome/browser/first_run/first_run.h"
 #include "chrome/browser/first_run/upgrade_util_mac.h"
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 3f75235..e7f2d93 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -8,6 +8,7 @@
 import("//media/media_options.gni")
 import("//printing/buildflags/buildflags.gni")
 import("//testing/libfuzzer/fuzzer_test.gni")
+import("//third_party/libprotobuf-mutator/fuzzable_proto_library.gni")
 import("//third_party/protobuf/proto_library.gni")
 import("//ui/ozone/ozone.gni")
 
@@ -39,6 +40,7 @@
     "//components/policy/proto",
     "//components/signin/core/browser",
     "//content/app/resources",
+    "//mojo/public/cpp/bindings",
     "//ui/accessibility/mojom",
     "//ui/chromeos/resources",
     "//ui/chromeos/strings",
@@ -3023,6 +3025,7 @@
     "//device/bluetooth",
     "//google_apis:test_support",
     "//google_apis/drive:test_support",
+    "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system:system",
     "//services/data_decoder/public/cpp:test_support",
     "//services/device/public/cpp:test_support",
@@ -3169,3 +3172,29 @@
     "//chrome/browser/chromeos",
   ]
 }
+
+if (use_libfuzzer) {
+  fuzzer_test("policy_fuzzer") {
+    sources = [
+      "policy/fuzzer/policy_fuzzer.cc",
+    ]
+
+    deps = [
+      ":policy_fuzzer_proto",
+      "//chrome/browser",
+      "//chrome/browser/chromeos",
+      "//third_party/libprotobuf-mutator",
+    ]
+  }
+
+  fuzzable_proto_library("policy_fuzzer_proto") {
+    sources = [
+      "policy/fuzzer/policy_fuzzer.proto",
+    ]
+
+    import_dirs = [ "//components/policy/proto" ]
+
+    link_deps =
+        [ "//components/policy/proto:chrome_device_policy_full_runtime_proto" ]
+  }
+}
diff --git a/chrome/browser/chromeos/account_manager/account_manager_migrator.cc b/chrome/browser/chromeos/account_manager/account_manager_migrator.cc
index a3d51e6b..f5a2b6c 100644
--- a/chrome/browser/chromeos/account_manager/account_manager_migrator.cc
+++ b/chrome/browser/chromeos/account_manager/account_manager_migrator.cc
@@ -20,6 +20,7 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/account_manager/account_manager_util.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/arc/auth/arc_auth_service.h"
diff --git a/chrome/browser/chromeos/account_manager/account_manager_policy_controller_browsertest.cc b/chrome/browser/chromeos/account_manager/account_manager_policy_controller_browsertest.cc
index 4da29a5..2b3beb7 100644
--- a/chrome/browser/chromeos/account_manager/account_manager_policy_controller_browsertest.cc
+++ b/chrome/browser/chromeos/account_manager/account_manager_policy_controller_browsertest.cc
@@ -6,6 +6,7 @@
 #include "base/run_loop.h"
 #include "base/test/bind_test_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/account_manager/account_manager_policy_controller.h"
 #include "chrome/browser/chromeos/account_manager/account_manager_policy_controller_factory.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
diff --git a/chrome/browser/chromeos/account_manager/account_manager_policy_controller_factory.cc b/chrome/browser/chromeos/account_manager/account_manager_policy_controller_factory.cc
index 873cdc2..872b59f4 100644
--- a/chrome/browser/chromeos/account_manager/account_manager_policy_controller_factory.cc
+++ b/chrome/browser/chromeos/account_manager/account_manager_policy_controller_factory.cc
@@ -6,6 +6,7 @@
 
 #include "base/no_destructor.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/account_manager/account_manager_policy_controller.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/chromeos/account_manager/account_manager_util.cc b/chrome/browser/chromeos/account_manager/account_manager_util.cc
index 597e19c..fe7a633 100644
--- a/chrome/browser/chromeos/account_manager/account_manager_util.cc
+++ b/chrome/browser/chromeos/account_manager/account_manager_util.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/net/delay_network_call.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/net/system_network_context_manager.h"
diff --git a/chrome/browser/chromeos/app_mode/app_session.cc b/chrome/browser/chromeos/app_mode/app_session.cc
index 60684db..be14aa4 100644
--- a/chrome/browser/chromeos/app_mode/app_session.cc
+++ b/chrome/browser/chromeos/app_mode/app_session.cc
@@ -15,6 +15,7 @@
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_update_service.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_mode_idle_app_name_notification.h"
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
index 16ec49c..762c202 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
@@ -21,6 +21,7 @@
 #include "base/task/post_task.h"
 #include "base/version.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/app_mode/app_session.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_data.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_external_loader.h"
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc b/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc
index 68a4939..880234d3 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc
@@ -21,6 +21,7 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/app_mode/fake_cws.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_data.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h"
diff --git a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.cc b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.cc
index 22636e2..c933349b 100644
--- a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/arc/arc_optin_uma.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/dm_token_storage.h"
diff --git a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
index 432dcbb..acb00f31 100644
--- a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/task/post_task.h"
 #include "base/test/bind_test_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
 #include "chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h"
 #include "chrome/browser/chromeos/arc/extensions/fake_arc_support.h"
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
index d6d594b..c23b7becf 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
@@ -19,6 +19,7 @@
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/arc/auth/arc_auth_context.h"
 #include "chrome/browser/chromeos/arc/auth/arc_auth_service.h"
diff --git a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.cc b/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.cc
index bf1dcfe5..c7e20ca 100644
--- a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "components/policy/core/common/cloud/device_management_service.h"
diff --git a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc
index 585ef94..ac6f50e 100644
--- a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc
@@ -13,6 +13,7 @@
 #include "base/task/post_task.h"
 #include "base/test/bind_test_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/arc/auth/arc_auth_service.h"
 #include "chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
diff --git a/chrome/browser/chromeos/arc/notification/arc_boot_error_notification.cc b/chrome/browser/chromeos/arc/notification/arc_boot_error_notification.cc
index f259175..7d06e09 100644
--- a/chrome/browser/chromeos/arc/notification/arc_boot_error_notification.cc
+++ b/chrome/browser/chromeos/arc/notification/arc_boot_error_notification.cc
@@ -14,6 +14,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/notifications/notification_display_service.h"
 #include "chrome/browser/notifications/notification_display_service_factory.h"
diff --git a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc
index 7292573..1764195 100644
--- a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc
+++ b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc
@@ -96,7 +96,7 @@
         ConsentAuditorFactory::GetForProfile(profile()));
   }
 
-  std::string GetAuthenticatedAccountId() {
+  CoreAccountId GetAuthenticatedAccountId() {
     return IdentityManagerFactory::GetForProfile(profile())
         ->GetPrimaryAccountInfo()
         .account_id;
diff --git a/chrome/browser/chromeos/arc/session/arc_play_store_enabled_preference_handler_unittest.cc b/chrome/browser/chromeos/arc/session/arc_play_store_enabled_preference_handler_unittest.cc
index b1b31bcc3..1cbf7c8 100644
--- a/chrome/browser/chromeos/arc/session/arc_play_store_enabled_preference_handler_unittest.cc
+++ b/chrome/browser/chromeos/arc/session/arc_play_store_enabled_preference_handler_unittest.cc
@@ -112,7 +112,7 @@
         ConsentAuditorFactory::GetForProfile(profile()));
   }
 
-  std::string GetAuthenticatedAccountId() const {
+  CoreAccountId GetAuthenticatedAccountId() const {
     auto* identity_manager =
         identity_test_env_profile_adaptor_->identity_test_env()
             ->identity_manager();
diff --git a/chrome/browser/chromeos/arc/session/arc_service_launcher.cc b/chrome/browser/chromeos/arc/session/arc_service_launcher.cc
index ad709ae..2c2421e 100644
--- a/chrome/browser/chromeos/arc/session/arc_service_launcher.cc
+++ b/chrome/browser/chromeos/arc/session/arc_service_launcher.cc
@@ -82,6 +82,7 @@
 #include "components/arc/wake_lock/arc_wake_lock_bridge.h"
 #include "components/prefs/pref_member.h"
 #include "content/public/browser/system_connector.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 namespace arc {
@@ -119,9 +120,11 @@
                      base::FilePath(kIsArcVm),
                      arc::IsArcVmEnabled() ? "1" : "0", 1));
 
-  ash::mojom::CrosDisplayConfigControllerPtr cros_display_config;
-  content::GetSystemConnector()->BindInterface(ash::mojom::kServiceName,
-                                               &cros_display_config);
+  mojo::PendingRemote<ash::mojom::CrosDisplayConfigController>
+      cros_display_config;
+  content::GetSystemConnector()->Connect(
+      ash::mojom::kServiceName,
+      cros_display_config.InitWithNewPipeAndPassReceiver());
   default_scale_factor_retriever_.Start(std::move(cros_display_config));
 }
 
diff --git a/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc b/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc
index fde0366..a6a54a67 100644
--- a/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc
+++ b/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc
@@ -15,6 +15,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/notifications/notification_common.h"
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index 10907588..d291d55 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -21,6 +21,7 @@
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/crostini/ansible/ansible_management_service.h"
 #include "chrome/browser/chromeos/crostini/crostini_features.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager_factory.h"
@@ -1306,82 +1307,6 @@
                      weak_ptr_factory_.GetWeakPtr(), std::move(key)));
 }
 
-namespace {
-vm_tools::cicerone::UpgradeContainerRequest::Version ConvertVersion(
-    ContainerVersion from) {
-  switch (from) {
-    case ContainerVersion::STRETCH:
-      return vm_tools::cicerone::UpgradeContainerRequest::DEBIAN_STRETCH;
-    case ContainerVersion::BUSTER:
-      return vm_tools::cicerone::UpgradeContainerRequest::DEBIAN_BUSTER;
-    case ContainerVersion::UNKNOWN:
-    default:
-      return vm_tools::cicerone::UpgradeContainerRequest::UNKNOWN;
-  }
-}
-
-}  // namespace
-
-void CrostiniManager::UpgradeContainer(const ContainerId& key,
-                                       ContainerVersion source_version,
-                                       ContainerVersion target_version,
-                                       CrostiniResultCallback callback) {
-  const auto& vm_name = key.vm_name;
-  const auto& container_name = key.container_name;
-  if (vm_name.empty()) {
-    LOG(ERROR) << "vm_name is required";
-    std::move(callback).Run(CrostiniResult::CLIENT_ERROR);
-    return;
-  }
-  if (container_name.empty()) {
-    LOG(ERROR) << "container_name is required";
-    std::move(callback).Run(CrostiniResult::CLIENT_ERROR);
-    return;
-  }
-  if (!GetCiceroneClient()->IsUpgradeContainerProgressSignalConnected()) {
-    // Technically we could still start the upgrade, but we wouldn't be able to
-    // detect when the upgrade completes, successfully or otherwise.
-    LOG(ERROR)
-        << "Attempted to upgrade container when progress signal not connected.";
-    std::move(callback).Run(CrostiniResult::UPGRADE_CONTAINER_FAILED);
-    return;
-  }
-  vm_tools::cicerone::UpgradeContainerRequest request;
-  request.set_owner_id(owner_id_);
-  request.set_vm_name(vm_name);
-  request.set_container_name(container_name);
-  request.set_source_version(ConvertVersion(source_version));
-  request.set_target_version(ConvertVersion(target_version));
-  GetCiceroneClient()->UpgradeContainer(
-      std::move(request),
-      base::BindOnce(&CrostiniManager::OnUpgradeContainer,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void CrostiniManager::CancelUpgradeContainer(const ContainerId& key,
-                                             CrostiniResultCallback callback) {
-  const auto& vm_name = key.vm_name;
-  const auto& container_name = key.container_name;
-  if (vm_name.empty()) {
-    LOG(ERROR) << "vm_name is required";
-    std::move(callback).Run(CrostiniResult::CLIENT_ERROR);
-    return;
-  }
-  if (container_name.empty()) {
-    LOG(ERROR) << "container_name is required";
-    std::move(callback).Run(CrostiniResult::CLIENT_ERROR);
-    return;
-  }
-  vm_tools::cicerone::CancelUpgradeContainerRequest request;
-  request.set_owner_id(owner_id_);
-  request.set_vm_name(vm_name);
-  request.set_container_name(container_name);
-  GetCiceroneClient()->CancelUpgradeContainer(
-      std::move(request),
-      base::BindOnce(&CrostiniManager::OnCancelUpgradeContainer,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
 void CrostiniManager::LaunchContainerApplication(
     std::string vm_name,
     std::string container_name,
@@ -1825,16 +1750,6 @@
   import_container_progress_observers_.RemoveObserver(observer);
 }
 
-void CrostiniManager::AddUpgradeContainerProgressObserver(
-    UpgradeContainerProgressObserver* observer) {
-  upgrade_container_progress_observers_.AddObserver(observer);
-}
-
-void CrostiniManager::RemoveUpgradeContainerProgressObserver(
-    UpgradeContainerProgressObserver* observer) {
-  upgrade_container_progress_observers_.RemoveObserver(observer);
-}
-
 void CrostiniManager::AddVmShutdownObserver(VmShutdownObserver* observer) {
   vm_shutdown_observers_.AddObserver(observer);
 }
@@ -2231,41 +2146,6 @@
       ->OnApplyAnsiblePlaybookProgress(signal.status());
 }
 
-void CrostiniManager::OnUpgradeContainerProgress(
-    const vm_tools::cicerone::UpgradeContainerProgressSignal& signal) {
-  if (signal.owner_id() != owner_id_)
-    return;
-
-  UpgradeContainerProgressStatus status;
-  switch (signal.status()) {
-    case vm_tools::cicerone::UpgradeContainerProgressSignal::SUCCEEDED:
-      status = UpgradeContainerProgressStatus::SUCCEEDED;
-      break;
-    case vm_tools::cicerone::UpgradeContainerProgressSignal::UNKNOWN:
-    case vm_tools::cicerone::UpgradeContainerProgressSignal::FAILED:
-      status = UpgradeContainerProgressStatus::FAILED;
-      LOG(ERROR) << "Upgrade failed: " << signal.failure_reason();
-      break;
-    case vm_tools::cicerone::UpgradeContainerProgressSignal::IN_PROGRESS:
-      status = UpgradeContainerProgressStatus::UPGRADING;
-      break;
-    default:
-      NOTREACHED();
-  }
-
-  std::vector<const std::string> progress_messages;
-  progress_messages.reserve(signal.progress_messages().size());
-  for (const auto& msg : signal.progress_messages()) {
-    progress_messages.push_back(msg);
-  }
-
-  ContainerId container_id(signal.vm_name(), signal.container_name());
-  for (auto& observer : upgrade_container_progress_observers_) {
-    observer.OnUpgradeContainerProgress(container_id, status,
-                                        progress_messages);
-  }
-}
-
 void CrostiniManager::OnUninstallPackageOwningFile(
     CrostiniResultCallback callback,
     base::Optional<vm_tools::cicerone::UninstallPackageOwningFileResponse>
@@ -2929,66 +2809,6 @@
   }
 }
 
-void CrostiniManager::OnUpgradeContainer(
-    CrostiniResultCallback callback,
-    base::Optional<vm_tools::cicerone::UpgradeContainerResponse> response) {
-  if (!response) {
-    LOG(ERROR) << "Failed to start upgrading container. Empty response";
-    std::move(callback).Run(CrostiniResult::UPGRADE_CONTAINER_FAILED);
-    return;
-  }
-  CrostiniResult result = CrostiniResult::SUCCESS;
-  switch (response->status()) {
-    case vm_tools::cicerone::UpgradeContainerResponse::STARTED:
-      break;
-    case vm_tools::cicerone::UpgradeContainerResponse::ALREADY_RUNNING:
-      result = CrostiniResult::UPGRADE_CONTAINER_ALREADY_RUNNING;
-      LOG(ERROR) << "Upgrade already running. Nothing to do.";
-      break;
-    case vm_tools::cicerone::UpgradeContainerResponse::ALREADY_UPGRADED:
-      LOG(ERROR) << "Container already upgraded. Nothing to do.";
-      result = CrostiniResult::UPGRADE_CONTAINER_ALREADY_UPGRADED;
-      break;
-    case vm_tools::cicerone::UpgradeContainerResponse::NOT_SUPPORTED:
-      result = CrostiniResult::UPGRADE_CONTAINER_NOT_SUPPORTED;
-      break;
-    case vm_tools::cicerone::UpgradeContainerResponse::UNKNOWN:
-    case vm_tools::cicerone::UpgradeContainerResponse::FAILED:
-    default:
-      LOG(ERROR) << "Upgrade container failed. Failure reason "
-                 << response->failure_reason();
-      result = CrostiniResult::UPGRADE_CONTAINER_FAILED;
-      break;
-  }
-  std::move(callback).Run(result);
-}
-
-void CrostiniManager::OnCancelUpgradeContainer(
-    CrostiniResultCallback callback,
-    base::Optional<vm_tools::cicerone::CancelUpgradeContainerResponse>
-        response) {
-  if (!response) {
-    LOG(ERROR) << "Failed to cancel upgrading container. Empty response";
-    std::move(callback).Run(CrostiniResult::CANCEL_UPGRADE_CONTAINER_FAILED);
-    return;
-  }
-  CrostiniResult result = CrostiniResult::SUCCESS;
-  switch (response->status()) {
-    case vm_tools::cicerone::CancelUpgradeContainerResponse::CANCELLED:
-    case vm_tools::cicerone::CancelUpgradeContainerResponse::NOT_RUNNING:
-      break;
-
-    case vm_tools::cicerone::CancelUpgradeContainerResponse::UNKNOWN:
-    case vm_tools::cicerone::CancelUpgradeContainerResponse::FAILED:
-    default:
-      LOG(ERROR) << "Cancel upgrade container failed. Failure reason "
-                 << response->failure_reason();
-      result = CrostiniResult::CANCEL_UPGRADE_CONTAINER_FAILED;
-      break;
-  }
-  std::move(callback).Run(result);
-}
-
 void CrostiniManager::OnPendingAppListUpdates(
     const vm_tools::cicerone::PendingAppListUpdatesSignal& signal) {
   ContainerId container_id(signal.vm_name(), signal.container_name());
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h
index 9af46e8..9ec8b5119 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.h
+++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -90,14 +90,6 @@
       uint64_t minimum_required_space) = 0;
 };
 
-class UpgradeContainerProgressObserver {
- public:
-  virtual void OnUpgradeContainerProgress(
-      const ContainerId& container_id,
-      UpgradeContainerProgressStatus status,
-      const std::vector<const std::string>& messages) = 0;
-};
-
 class InstallerViewStatusObserver : public base::CheckedObserver {
  public:
   // Called when the CrostiniInstallerView is opened or closed.
@@ -283,19 +275,6 @@
   // CiceroneClient::CancelImportLxdContainer.
   void CancelImportLxdContainer(ContainerId key);
 
-  // Checks the arguments for upgrading an existing container via
-  // CiceroneClient::UpgradeContainer. An UpgradeProgressObserver should be used
-  // to monitor further results.
-  void UpgradeContainer(const ContainerId& key,
-                        ContainerVersion source_version,
-                        ContainerVersion target_version,
-                        CrostiniResultCallback callback);
-
-  // Checks the arguments for canceling the upgrade of an existing container via
-  // CiceroneClient::CancelUpgradeContainer.
-  void CancelUpgradeContainer(const ContainerId& key,
-                              CrostiniResultCallback callback);
-
   // Asynchronously launches an app as specified by its desktop file id.
   void LaunchContainerApplication(std::string vm_name,
                                   std::string container_name,
@@ -441,12 +420,6 @@
   void RemoveImportContainerProgressObserver(
       ImportContainerProgressObserver* observer);
 
-  // Add/remove observers for container upgrade
-  void AddUpgradeContainerProgressObserver(
-      UpgradeContainerProgressObserver* observer);
-  void RemoveUpgradeContainerProgressObserver(
-      UpgradeContainerProgressObserver* observer);
-
   // Add/remove vm shutdown observers.
   void AddVmShutdownObserver(VmShutdownObserver* observer);
   void RemoveVmShutdownObserver(VmShutdownObserver* observer);
@@ -491,9 +464,6 @@
   void OnApplyAnsiblePlaybookProgress(
       const vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal& signal)
       override;
-  void OnUpgradeContainerProgress(
-      const vm_tools::cicerone::UpgradeContainerProgressSignal& signal)
-      override;
 
   // chromeos::PowerManagerClient::Observer overrides:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
@@ -671,17 +641,6 @@
       base::Optional<vm_tools::cicerone::CancelImportLxdContainerResponse>
           response);
 
-  // Callback for CiceroneClient::UpgradeContainer.
-  void OnUpgradeContainer(
-      CrostiniResultCallback callback,
-      base::Optional<vm_tools::cicerone::UpgradeContainerResponse> response);
-
-  // Callback for CiceroneClient::CancelUpgradeContainer.
-  void OnCancelUpgradeContainer(
-      CrostiniResultCallback callback,
-      base::Optional<vm_tools::cicerone::CancelUpgradeContainerResponse>
-          response);
-
   // Callback for CrostiniManager::LaunchContainerApplication.
   void OnLaunchContainerApplication(
       BoolCallback callback,
@@ -812,9 +771,6 @@
   base::ObserverList<ImportContainerProgressObserver>::Unchecked
       import_container_progress_observers_;
 
-  base::ObserverList<UpgradeContainerProgressObserver>::Unchecked
-      upgrade_container_progress_observers_;
-
   base::ObserverList<VmShutdownObserver> vm_shutdown_observers_;
 
   // Only one restarter flow is actually running for a given container, other
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
index fc103f7..4287954e 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -1587,89 +1587,4 @@
   run_loop()->Run();
 }
 
-class CrostiniManagerUpgradeContainerTest
-    : public CrostiniManagerTest,
-      public UpgradeContainerProgressObserver {
- public:
-  void SetUp() override {
-    CrostiniManagerTest::SetUp();
-    progress_signal_.set_owner_id(CryptohomeIdForProfile(profile()));
-    progress_signal_.set_vm_name(kVmName);
-    progress_signal_.set_container_name(kContainerName);
-    progress_run_loop_ = std::make_unique<base::RunLoop>();
-    crostini_manager()->AddUpgradeContainerProgressObserver(this);
-  }
-
-  void TearDown() override {
-    crostini_manager()->RemoveUpgradeContainerProgressObserver(this);
-    progress_run_loop_.reset();
-    CrostiniManagerTest::TearDown();
-  }
-
-  void RunUntilUpgradeDone(UpgradeContainerProgressStatus final_status) {
-    final_status_ = final_status;
-    progress_run_loop_->Run();
-  }
-
-  void SendProgressSignal() {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(
-            &chromeos::FakeCiceroneClient::NotifyUpgradeContainerProgress,
-            base::Unretained(fake_cicerone_client_), progress_signal_));
-  }
-
- protected:
-  // UpgradeContainerProgressObserver
-  void OnUpgradeContainerProgress(
-      const ContainerId& container_id,
-      UpgradeContainerProgressStatus status,
-      const std::vector<const std::string>& messages) override {
-    if (status == final_status_) {
-      progress_run_loop_->Quit();
-    }
-  }
-
-  ContainerId container_id_ = ContainerId(kVmName, kContainerName);
-  UpgradeContainerProgressStatus final_status_;
-  vm_tools::cicerone::UpgradeContainerProgressSignal progress_signal_;
-  // must be created on UI thread
-  std::unique_ptr<base::RunLoop> progress_run_loop_;
-};
-
-TEST_F(CrostiniManagerUpgradeContainerTest, UpgradeContainerSuccess) {
-  crostini_manager()->UpgradeContainer(
-      container_id_, ContainerVersion::STRETCH, ContainerVersion::BUSTER,
-      base::BindOnce(&ExpectCrostiniResult, run_loop()->QuitClosure(),
-                     CrostiniResult::SUCCESS));
-
-  run_loop()->Run();
-
-  progress_signal_.set_status(
-      vm_tools::cicerone::UpgradeContainerProgressSignal::SUCCEEDED);
-
-  SendProgressSignal();
-  RunUntilUpgradeDone(UpgradeContainerProgressStatus::SUCCEEDED);
-}
-
-TEST_F(CrostiniManagerUpgradeContainerTest, CancelUpgradeContainerSuccess) {
-  crostini_manager()->UpgradeContainer(
-      container_id_, ContainerVersion::STRETCH, ContainerVersion::BUSTER,
-      base::BindOnce(&ExpectCrostiniResult, run_loop()->QuitClosure(),
-                     CrostiniResult::SUCCESS));
-
-  progress_signal_.set_status(
-      vm_tools::cicerone::UpgradeContainerProgressSignal::IN_PROGRESS);
-
-  SendProgressSignal();
-  run_loop()->Run();
-
-  base::RunLoop run_loop2;
-  crostini_manager()->CancelUpgradeContainer(
-      container_id_,
-      base::BindOnce(&ExpectCrostiniResult, run_loop2.QuitClosure(),
-                     CrostiniResult::SUCCESS));
-  run_loop2.Run();
-}
-
 }  // namespace crostini
diff --git a/chrome/browser/chromeos/crostini/crostini_simple_types.h b/chrome/browser/chromeos/crostini/crostini_simple_types.h
index 946d9ca9..9f38e22 100644
--- a/chrome/browser/chromeos/crostini/crostini_simple_types.h
+++ b/chrome/browser/chromeos/crostini/crostini_simple_types.h
@@ -63,13 +63,7 @@
   CONTAINER_EXPORT_IMPORT_CANCELLED = 37,
   RESTART_ABORTED = 38,
   RESTART_FAILED_VM_STOPPED = 39,
-  UPGRADE_CONTAINER_STARTED = 40,
-  UPGRADE_CONTAINER_ALREADY_RUNNING = 41,
-  UPGRADE_CONTAINER_NOT_SUPPORTED = 42,
-  UPGRADE_CONTAINER_ALREADY_UPGRADED = 43,
-  UPGRADE_CONTAINER_FAILED = 44,
-  CANCEL_UPGRADE_CONTAINER_FAILED = 45,
-  kMaxValue = CANCEL_UPGRADE_CONTAINER_FAILED,
+  kMaxValue = RESTART_FAILED_VM_STOPPED,
 };
 
 enum class InstallLinuxPackageProgressStatus {
@@ -107,18 +101,6 @@
   FAILURE_SPACE,
 };
 
-enum class UpgradeContainerProgressStatus {
-  SUCCEEDED,
-  FAILED,
-  UPGRADING,
-};
-
-enum class ContainerVersion {
-  UNKNOWN,
-  STRETCH,
-  BUSTER,
-};
-
 struct VmInfo {
   VmState state;
   vm_tools::concierge::VmInfo info;
diff --git a/chrome/browser/chromeos/dbus/plugin_vm_service_provider.cc b/chrome/browser/chromeos/dbus/plugin_vm_service_provider.cc
index a9dd6d3..16f0a88f 100644
--- a/chrome/browser/chromeos/dbus/plugin_vm_service_provider.cc
+++ b/chrome/browser/chromeos/dbus/plugin_vm_service_provider.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
diff --git a/chrome/browser/chromeos/eol_notification.cc b/chrome/browser/chromeos/eol_notification.cc
index 8e5413f..08b69c4 100644
--- a/chrome/browser/chromeos/eol_notification.cc
+++ b/chrome/browser/chromeos/eol_notification.cc
@@ -10,6 +10,7 @@
 #include "base/time/default_clock.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/notifications/notification_display_service.h"
 #include "chrome/browser/notifications/notification_display_service_factory.h"
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
index 79eac27e..07bc0b07 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -41,6 +41,7 @@
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
 #include "chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.h"
diff --git a/chrome/browser/chromeos/extensions/info_private_api.cc b/chrome/browser/chromeos/extensions/info_private_api.cc
index dafa0e0..0aaf258a 100644
--- a/chrome/browser/chromeos/extensions/info_private_api.cc
+++ b/chrome/browser/chromeos/extensions/info_private_api.cc
@@ -17,6 +17,7 @@
 #include "base/values.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
diff --git a/chrome/browser/chromeos/extensions/login_screen/login/login_apitest.cc b/chrome/browser/chromeos/extensions/login_screen/login/login_apitest.cc
index 243ed5a..f6ce58f 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login/login_apitest.cc
+++ b/chrome/browser/chromeos/extensions/login_screen/login/login_apitest.cc
@@ -11,11 +11,12 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/extensions/login_screen/login_screen_apitest_base.h"
 #include "chrome/browser/chromeos/login/test/local_policy_test_server_mixin.h"
+#include "chrome/browser/chromeos/login/test/session_manager_state_waiter.h"
 #include "chrome/common/pref_names.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #include "components/prefs/pref_service.h"
-#include "components/session_manager/core/session_manager.h"
+#include "components/session_manager/session_manager_types.h"
 #include "components/user_manager/user_type.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/notification_observer.h"
@@ -69,11 +70,10 @@
   DISALLOW_COPY_AND_ASSIGN(LoginApitest);
 };
 
-// Flaky. https://crbug.com/1014239
-IN_PROC_BROWSER_TEST_F(LoginApitest, DISABLED_LaunchManagedGuestSession) {
+IN_PROC_BROWSER_TEST_F(LoginApitest, LaunchManagedGuestSession) {
   SetUpDeviceLocalAccountPolicy();
   SetUpExtensionAndRunTest(kLaunchManagedGuestSession);
-  EXPECT_TRUE(session_manager::SessionManager::Get()->IsSessionStarted());
+  SessionStateWaiter(session_manager::SessionState::ACTIVE).Wait();
 
   // Check that the active user is of type |USER_TYPE_PUBLIC_ACCOUNT|.
   // We cannot use the email as an identifier as a different email is generated
diff --git a/chrome/browser/chromeos/extensions/users_private/users_private_api.cc b/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
index f8bbf22..a962595 100644
--- a/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
+++ b/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
@@ -13,6 +13,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/extensions/users_private/users_private_delegate.h"
 #include "chrome/browser/chromeos/extensions/users_private/users_private_delegate_factory.h"
 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h"
diff --git a/chrome/browser/chromeos/file_manager/file_tasks_notifier_unittest.cc b/chrome/browser/chromeos/file_manager/file_tasks_notifier_unittest.cc
index a55f98e..bb817cb2 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks_notifier_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks_notifier_unittest.cc
@@ -15,10 +15,13 @@
 #include "chrome/browser/chromeos/file_manager/file_tasks_observer.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/components/drivefs/mojom/drivefs.mojom-test-utils.h"
+#include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
 #include "components/drive/file_errors.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/fake_download_item.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "storage/browser/fileapi/external_mount_points.h"
 #include "storage/browser/fileapi/file_system_url.h"
 #include "storage/common/fileapi/file_system_types.h"
@@ -97,7 +100,8 @@
 
 class FileTasksNotifierForTest : public FileTasksNotifier {
  public:
-  FileTasksNotifierForTest(Profile* profile, drivefs::mojom::DriveFsPtr drivefs)
+  FileTasksNotifierForTest(Profile* profile,
+                           mojo::PendingRemote<drivefs::mojom::DriveFs> drivefs)
       : FileTasksNotifier(profile), drivefs_(std::move(drivefs)) {}
 
   drivefs::mojom::DriveFs* GetDriveFsInterface() override {
@@ -115,21 +119,19 @@
   void set_is_offline(bool is_offline) { is_offline_ = is_offline; }
 
  private:
-  const drivefs::mojom::DriveFsPtr drivefs_;
+  const mojo::Remote<drivefs::mojom::DriveFs> drivefs_;
   bool is_offline_ = false;
 };
 
 class FileTasksNotifierTest : public testing::Test {
  protected:
-  FileTasksNotifierTest() : drivefs_binding_(&fake_drivefs_) {}
+  FileTasksNotifierTest() = default;
 
   void SetUp() override {
     profile_ = std::make_unique<TestingProfile>();
 
-    drivefs::mojom::DriveFsPtr fake_drivefs_ptr;
-    drivefs_binding_.Bind(mojo::MakeRequest(&fake_drivefs_ptr));
     notifier_ = std::make_unique<FileTasksNotifierForTest>(
-        profile_.get(), std::move(fake_drivefs_ptr));
+        profile_.get(), drivefs_receiver_.BindNewPipeAndPassRemote());
     observer_ = std::make_unique<MockFileTasksObserver>(notifier_.get());
 
     auto* mount_points = storage::ExternalMountPoints::GetSystemInstance();
@@ -175,7 +177,7 @@
  private:
   content::BrowserTaskEnvironment task_environment_;
   FakeDriveFs fake_drivefs_;
-  mojo::Binding<drivefs::mojom::DriveFs> drivefs_binding_;
+  mojo::Receiver<drivefs::mojom::DriveFs> drivefs_receiver_{&fake_drivefs_};
   std::unique_ptr<TestingProfile> profile_;
   std::unique_ptr<FileTasksNotifierForTest> notifier_;
   std::unique_ptr<MockFileTasksObserver> observer_;
diff --git a/chrome/browser/chromeos/fileapi/external_file_url_loader_factory.cc b/chrome/browser/chromeos/fileapi/external_file_url_loader_factory.cc
index c1b10c9..5e09210 100644
--- a/chrome/browser/chromeos/fileapi/external_file_url_loader_factory.cc
+++ b/chrome/browser/chromeos/fileapi/external_file_url_loader_factory.cc
@@ -30,6 +30,7 @@
 #include "net/http/http_byte_range.h"
 #include "net/http/http_util.h"
 #include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
 #include "storage/browser/fileapi/file_stream_reader.h"
 #include "storage/browser/fileapi/file_system_backend.h"
 #include "storage/browser/fileapi/file_system_context.h"
diff --git a/chrome/browser/chromeos/fileapi/recent_drive_source.cc b/chrome/browser/chromeos/fileapi/recent_drive_source.cc
index e85cfdb..5c8b292 100644
--- a/chrome/browser/chromeos/fileapi/recent_drive_source.cc
+++ b/chrome/browser/chromeos/fileapi/recent_drive_source.cc
@@ -65,7 +65,7 @@
   query_params->sort_direction =
       drivefs::mojom::QueryParameters::SortDirection::kDescending;
   integration_service->GetDriveFsInterface()->StartSearchQuery(
-      mojo::MakeRequest(&search_query_), std::move(query_params));
+      search_query_.BindNewPipeAndPassReceiver(), std::move(query_params));
   search_query_->GetNextPage(base::BindOnce(
       &RecentDriveSource::GotSearchResults, weak_ptr_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/chromeos/fileapi/recent_drive_source.h b/chrome/browser/chromeos/fileapi/recent_drive_source.h
index 011b2a48..c63308a 100644
--- a/chrome/browser/chromeos/fileapi/recent_drive_source.h
+++ b/chrome/browser/chromeos/fileapi/recent_drive_source.h
@@ -17,6 +17,7 @@
 #include "chrome/browser/chromeos/fileapi/recent_source.h"
 #include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
 #include "components/drive/file_errors.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 class Profile;
 
@@ -55,7 +56,7 @@
 
   std::vector<RecentFile> files_;
 
-  drivefs::mojom::SearchQueryPtr search_query_;
+  mojo::Remote<drivefs::mojom::SearchQuery> search_query_;
 
   base::WeakPtrFactory<RecentDriveSource> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/chromeos/first_run/goodies_displayer.cc b/chrome/browser/chromeos/first_run/goodies_displayer.cc
index 8dd74db0..39287eb 100644
--- a/chrome/browser/chromeos/first_run/goodies_displayer.cc
+++ b/chrome/browser/chromeos/first_run/goodies_displayer.cc
@@ -11,6 +11,7 @@
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/chromeos/hats/hats_notification_controller.cc b/chrome/browser/chromeos/hats/hats_notification_controller.cc
index ebb55fa..5e095eb 100644
--- a/chrome/browser/chromeos/hats/hats_notification_controller.cc
+++ b/chrome/browser/chromeos/hats/hats_notification_controller.cc
@@ -11,6 +11,7 @@
 #include "base/task/post_task.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/hats/hats_dialog.h"
 #include "chrome/browser/chromeos/hats/hats_finch_helper.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
index 347a5ee4..96658c6 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
@@ -1465,7 +1465,7 @@
 TEST_F(InputMethodManagerImplTest, IntegrationWithAsh) {
   TestImeController ime_controller;  // Mojo interface to ash.
   ImeControllerClient ime_controller_client(manager_.get());
-  ime_controller_client.InitForTesting(ime_controller.CreateInterfacePtr());
+  ime_controller_client.InitForTesting(ime_controller.CreateRemote());
 
   // Setup 3 IMEs.
   InitComponentExtension();
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller.cc b/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
index 7957a4de..e23bba41 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
@@ -8,6 +8,7 @@
 
 #include "ash/public/cpp/stylus_utils.h"
 #include "ash/public/mojom/constants.mojom.h"
+#include "ash/public/mojom/tray_action.mojom.h"
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -37,6 +38,7 @@
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/app_window/native_app_window.h"
 #include "extensions/common/extension.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/wm/core/window_animations.h"
 
@@ -87,13 +89,13 @@
   g_state_controller_instance = nullptr;
 }
 
-void StateController::SetTrayActionPtrForTesting(
-    ash::mojom::TrayActionPtr tray_action_ptr) {
-  tray_action_ptr_ = std::move(tray_action_ptr);
+void StateController::SetTrayActionForTesting(
+    mojo::PendingRemote<ash::mojom::TrayAction> tray_action) {
+  tray_action_.Bind(std::move(tray_action));
 }
 
 void StateController::FlushTrayActionForTesting() {
-  tray_action_ptr_.FlushForTesting();
+  tray_action_.FlushForTesting();
 }
 
 void StateController::SetReadyCallbackForTesting(
@@ -126,13 +128,13 @@
 
   // The tray action ptr might be set previously if the client was being created
   // for testing.
-  if (!tray_action_ptr_) {
-    content::GetSystemConnector()->BindInterface(ash::mojom::kServiceName,
-                                                 &tray_action_ptr_);
+  if (!tray_action_) {
+    content::GetSystemConnector()->Connect(
+        ash::mojom::kServiceName, tray_action_.BindNewPipeAndPassReceiver());
   }
-  ash::mojom::TrayActionClientPtr client;
-  binding_.Bind(mojo::MakeRequest(&client));
-  tray_action_ptr_->SetClient(std::move(client), lock_screen_note_state_);
+  mojo::PendingRemote<ash::mojom::TrayActionClient> client;
+  receiver_.Bind(client.InitWithNewPipeAndPassReceiver());
+  tray_action_->SetClient(std::move(client), lock_screen_note_state_);
 }
 
 void StateController::SetPrimaryProfile(Profile* profile) {
@@ -167,7 +169,7 @@
   focus_cycler_delegate_ = nullptr;
   power_manager_client_observer_.RemoveAll();
   input_devices_observer_.RemoveAll();
-  binding_.Close();
+  receiver_.reset();
   weak_ptr_factory_.InvalidateWeakPtrs();
 }
 
@@ -506,7 +508,7 @@
   for (auto& observer : observers_)
     observer.OnLockScreenNoteStateChanged(lock_screen_note_state_);
 
-  tray_action_ptr_->UpdateLockScreenNoteState(lock_screen_note_state_);
+  tray_action_->UpdateLockScreenNoteState(lock_screen_note_state_);
 }
 
 }  // namespace lock_screen_apps
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller.h b/chrome/browser/chromeos/lock_screen_apps/state_controller.h
index 1fef6ce..254577c 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller.h
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller.h
@@ -21,7 +21,9 @@
 #include "components/session_manager/core/session_manager_observer.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/common/api/app_runtime.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "ui/aura/window.h"
 #include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/input_device_event_observer.h"
@@ -78,7 +80,8 @@
 
   // Sets the tray action that should be used by |StateController|.
   // Has to be called before |Initialize|.
-  void SetTrayActionPtrForTesting(ash::mojom::TrayActionPtr tray_action_ptr);
+  void SetTrayActionForTesting(
+      mojo::PendingRemote<ash::mojom::TrayAction> tray_action);
   void FlushTrayActionForTesting();
   // Sets the callback that will be run when the state controller is fully
   // initialized and ready for action.
@@ -210,8 +213,8 @@
 
   base::ObserverList<StateObserver>::Unchecked observers_;
 
-  mojo::Binding<ash::mojom::TrayActionClient> binding_{this};
-  ash::mojom::TrayActionPtr tray_action_ptr_;
+  mojo::Receiver<ash::mojom::TrayActionClient> receiver_{this};
+  mojo::Remote<ash::mojom::TrayAction> tray_action_;
 
   std::unique_ptr<LockScreenProfileCreator> lock_screen_profile_creator_;
 
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc b/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc
index 1bfe869..911b312 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc
@@ -55,6 +55,9 @@
 #include "extensions/common/api/app_runtime.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/value_builder.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/window.h"
 #include "ui/events/devices/device_data_manager.h"
@@ -266,19 +269,19 @@
 
 class TestTrayAction : public ash::mojom::TrayAction {
  public:
-  TestTrayAction() : binding_(this) {}
+  TestTrayAction() = default;
 
   ~TestTrayAction() override = default;
 
-  ash::mojom::TrayActionPtr CreateInterfacePtrAndBind() {
-    ash::mojom::TrayActionPtr ptr;
-    binding_.Bind(mojo::MakeRequest(&ptr));
-    return ptr;
+  mojo::PendingRemote<ash::mojom::TrayAction> CreateRemoteAndBind() {
+    mojo::PendingRemote<ash::mojom::TrayAction> remote;
+    receiver_.Bind(remote.InitWithNewPipeAndPassReceiver());
+    return remote;
   }
 
-  void SetClient(ash::mojom::TrayActionClientPtr client,
+  void SetClient(mojo::PendingRemote<ash::mojom::TrayActionClient> client,
                  TrayActionState state) override {
-    client_ = std::move(client);
+    client_.Bind(std::move(client));
     EXPECT_EQ(TrayActionState::kNotAvailable, state);
   }
 
@@ -298,8 +301,8 @@
   void ClearObservedStates() { observed_states_.clear(); }
 
  private:
-  mojo::Binding<ash::mojom::TrayAction> binding_;
-  ash::mojom::TrayActionClientPtr client_;
+  mojo::Receiver<ash::mojom::TrayAction> receiver_{this};
+  mojo::Remote<ash::mojom::TrayActionClient> client_;
 
   std::vector<TrayActionState> observed_states_;
 
@@ -414,8 +417,8 @@
     tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
 
     state_controller_ = std::make_unique<lock_screen_apps::StateController>();
-    state_controller_->SetTrayActionPtrForTesting(
-        tray_action_.CreateInterfacePtrAndBind());
+    state_controller_->SetTrayActionForTesting(
+        tray_action_.CreateRemoteAndBind());
     state_controller_->SetTickClockForTesting(&tick_clock_);
     state_controller_->SetLockScreenLockScreenProfileCreatorForTesting(
         std::move(profile_creator));
diff --git a/chrome/browser/chromeos/login/app_launch_controller.cc b/chrome/browser/chromeos/login/app_launch_controller.cc
index 92abb61..6075ad4 100644
--- a/chrome/browser/chromeos/login/app_launch_controller.cc
+++ b/chrome/browser/chromeos/login/app_launch_controller.cc
@@ -20,6 +20,7 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
diff --git a/chrome/browser/chromeos/login/auth/chrome_login_performer.cc b/chrome/browser/chromeos/login/auth/chrome_login_performer.cc
index 3cef8af..df417025 100644
--- a/chrome/browser/chromeos/login/auth/chrome_login_performer.cc
+++ b/chrome/browser/chromeos/login/auth/chrome_login_performer.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
diff --git a/chrome/browser/chromeos/login/configuration_based_oobe_browsertest.cc b/chrome/browser/chromeos/login/configuration_based_oobe_browsertest.cc
index 7a1cb8a1..fb24c5fc 100644
--- a/chrome/browser/chromeos/login/configuration_based_oobe_browsertest.cc
+++ b/chrome/browser/chromeos/login/configuration_based_oobe_browsertest.cc
@@ -5,6 +5,7 @@
 #include "base/system/sys_info.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_setup_controller.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_setup_test_utils.h"
 #include "chrome/browser/chromeos/login/test/enrollment_helper_mixin.h"
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc b/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc
index 7afa6a50..f95d119 100644
--- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc
+++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc
@@ -13,6 +13,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/auto_enrollment_client_impl.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/server_backed_state_keys_broker.h"
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc b/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
index 2f7fd8be..53f91ac8 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
@@ -6,6 +6,7 @@
 #include "base/bind.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h"
 #include "chrome/browser/chromeos/login/enrollment/enrollment_screen.h"
diff --git a/chrome/browser/chromeos/login/enterprise_user_session_metrics.cc b/chrome/browser/chromeos/login/enterprise_user_session_metrics.cc
index 3bedf34..d87ba53c 100644
--- a/chrome/browser/chromeos/login/enterprise_user_session_metrics.cc
+++ b/chrome/browser/chromeos/login/enterprise_user_session_metrics.cc
@@ -10,6 +10,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.cc b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
index 820763f2..6907dd1 100644
--- a/chrome/browser/chromeos/login/lock/views_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
@@ -20,6 +20,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/authpolicy/authpolicy_helper.h"
 #include "chrome/browser/chromeos/lock_screen_apps/state_controller.h"
 #include "chrome/browser/chromeos/login/challenge_response_auth_keys_loader.h"
diff --git a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
index 3c099b5d..95edb568 100644
--- a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
+++ b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <vector>
 
+#include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/chromeos/login/saml/public_saml_url_fetcher.cc b/chrome/browser/chromeos/login/saml/public_saml_url_fetcher.cc
index 623c33e2..5372fa6 100644
--- a/chrome/browser/chromeos/login/saml/public_saml_url_fetcher.cc
+++ b/chrome/browser/chromeos/login/saml/public_saml_url_fetcher.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/arc/arc_optin_uma.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.cc b/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.cc
index e89f8016..650ec9c 100644
--- a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.cc
+++ b/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.cc
@@ -275,7 +275,8 @@
       url_loader_factory_(url_loader_factory),
       arc_features_getter_(
           base::BindRepeating(&arc::ArcFeaturesParser::GetArcFeatures)) {
-  connector_->BindInterface(ash::mojom::kServiceName, &cros_display_config_);
+  connector_->Connect(ash::mojom::kServiceName,
+                      cros_display_config_.BindNewPipeAndPassReceiver());
 }
 
 RecommendAppsFetcherImpl::~RecommendAppsFetcherImpl() = default;
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.h b/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.h
index a311f22..1f5d261 100644
--- a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.h
+++ b/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.h
@@ -18,6 +18,7 @@
 #include "chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.h"
 #include "components/arc/arc_features_parser.h"
 #include "extensions/browser/api/system_display/display_info_provider.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace base {
 class Value;
@@ -157,7 +158,7 @@
 
   ArcFeaturesGetter arc_features_getter_;
 
-  ash::mojom::CrosDisplayConfigControllerPtr cros_display_config_;
+  mojo::Remote<ash::mojom::CrosDisplayConfigController> cros_display_config_;
   base::WeakPtrFactory<RecommendAppsFetcherImpl> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(RecommendAppsFetcherImpl);
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl_unittest.cc b/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl_unittest.cc
index ed2b1d3..370cd858 100644
--- a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl_unittest.cc
+++ b/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher_impl.h"
 
 #include <memory>
+#include <utility>
 #include <vector>
 
 #include "ash/public/mojom/constants.mojom.h"
@@ -24,7 +25,9 @@
 #include "components/arc/arc_features_parser.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "content/public/test/browser_task_environment.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/service.h"
@@ -80,7 +83,7 @@
       ready_callback_ = run_loop.QuitClosure();
       run_loop.Run();
     }
-    binding_.FlushForTesting();
+    receiver_.FlushForTesting();
   }
 
   bool RunGetDisplayUnitInfoListCallback(
@@ -93,8 +96,9 @@
   }
 
   // ash::mojom::CrosDisplayConfigController:
-  void AddObserver(ash::mojom::CrosDisplayConfigObserverAssociatedPtrInfo
-                       observer) override {}
+  void AddObserver(
+      mojo::PendingAssociatedRemote<ash::mojom::CrosDisplayConfigObserver>
+          observer) override {}
   void GetDisplayLayoutInfo(GetDisplayLayoutInfoCallback callback) override {}
   void SetDisplayLayoutInfo(ash::mojom::DisplayLayoutInfoPtr info,
                             SetDisplayLayoutInfoCallback callback) override {}
@@ -122,8 +126,9 @@
                        const std::string& interface_name,
                        mojo::ScopedMessagePipeHandle interface_pipe) override {
     DCHECK(interface_name == ash::mojom::CrosDisplayConfigController::Name_);
-    binding_.Bind(ash::mojom::CrosDisplayConfigControllerRequest(
-        std::move(interface_pipe)));
+    receiver_.Bind(
+        mojo::PendingReceiver<ash::mojom::CrosDisplayConfigController>(
+            std::move(interface_pipe)));
     ready_ = true;
     if (ready_callback_)
       std::move(ready_callback_).Run();
@@ -131,7 +136,7 @@
 
  private:
   service_manager::ServiceBinding service_binding_;
-  mojo::Binding<ash::mojom::CrosDisplayConfigController> binding_{this};
+  mojo::Receiver<ash::mojom::CrosDisplayConfigController> receiver_{this};
 
   bool ready_ = false;
   base::OnceClosure ready_callback_;
diff --git a/chrome/browser/chromeos/login/screens/reset_screen.cc b/chrome/browser/chromeos/login/screens/reset_screen.cc
index 6fbf857..268aa7c 100644
--- a/chrome/browser/chromeos/login/screens/reset_screen.cc
+++ b/chrome/browser/chromeos/login/screens/reset_screen.cc
@@ -12,6 +12,7 @@
 #include "base/task/post_task.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h"
 #include "chrome/browser/chromeos/login/screens/error_screen.h"
 #include "chrome/browser/chromeos/login/screens/network_error.h"
diff --git a/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc b/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc
index 39b3524..c56a8705 100644
--- a/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc
+++ b/chrome/browser/chromeos/login/screens/terms_of_service_screen.cc
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/net/system_network_context_manager.h"
diff --git a/chrome/browser/chromeos/login/test/local_policy_test_server_mixin.cc b/chrome/browser/chromeos/login/test/local_policy_test_server_mixin.cc
index 7cd3b89..41bd897 100644
--- a/chrome/browser/chromeos/login/test/local_policy_test_server_mixin.cc
+++ b/chrome/browser/chromeos/login/test/local_policy_test_server_mixin.cc
@@ -8,6 +8,7 @@
 
 #include "base/guid.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/login/test/fake_gaia_mixin.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_initializer.h"
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_common.cc b/chrome/browser/chromeos/login/ui/login_display_host_common.cc
index 38a646d..7c7cd0d 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_common.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_common.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/app_launch_controller.h"
 #include "chrome/browser/chromeos/login/arc_kiosk_controller.h"
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
index e5f0324d..489c76c 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -26,6 +26,7 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #include "chrome/browser/chromeos/base/locale_util.h"
diff --git a/chrome/browser/chromeos/login/users/affiliation.cc b/chrome/browser/chromeos/login/users/affiliation.cc
index ea8e92a4..ba4d116 100644
--- a/chrome/browser/chromeos/login/users/affiliation.cc
+++ b/chrome/browser/chromeos/login/users/affiliation.cc
@@ -8,6 +8,7 @@
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index 194b5c3..ee9c898 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -32,6 +32,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/extensions/active_tab_permission_granter_delegate_chromeos.h"
diff --git a/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc b/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc
index da21dac..a92de5d0 100644
--- a/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc
+++ b/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc
@@ -11,6 +11,7 @@
 #include "base/command_line.h"
 #include "base/system/sys_info.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/chrome_user_manager_util.h"
 #include "chrome/browser/chromeos/login/users/fake_supervised_user_manager.h"
diff --git a/chrome/browser/chromeos/login/version_info_updater.cc b/chrome/browser/chromeos/login/version_info_updater.cc
index cd099c9..38c2c66 100644
--- a/chrome/browser/chromeos/login/version_info_updater.cc
+++ b/chrome/browser/chromeos/login/version_info_updater.cc
@@ -14,6 +14,7 @@
 #include "base/system/sys_info.h"
 #include "base/task/post_task.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/grit/chromium_strings.h"
diff --git a/chrome/browser/chromeos/login/webview_login_browsertest.cc b/chrome/browser/chromeos/login/webview_login_browsertest.cc
index 98bdff12..f3c7353 100644
--- a/chrome/browser/chromeos/login/webview_login_browsertest.cc
+++ b/chrome/browser/chromeos/login/webview_login_browsertest.cc
@@ -21,6 +21,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/login/signin_partition_manager.h"
diff --git a/chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer_browsertest.cc b/chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer_browsertest.cc
index b38064a..0997bce4 100644
--- a/chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer_browsertest.cc
@@ -10,6 +10,7 @@
 #include "base/files/file_path.h"
 #include "base/path_service.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
index a4a7d686..5b9fcf6 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
@@ -433,8 +433,7 @@
           DeviceStatusCollector::TpmStatusFetcher(),
           DeviceStatusCollector::EMMCLifetimeFetcher(),
           DeviceStatusCollector::StatefulPartitionInfoFetcher(),
-          DeviceStatusCollector::CrosHealthdDataFetcher(),
-          true /* is_enterprise_device */),
+          DeviceStatusCollector::CrosHealthdDataFetcher()),
       task_runner_, kDeviceStatusUploadFrequency));
 }
 
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index deb5533..7a7cad6d 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -41,6 +41,7 @@
 #include "chrome/browser/apps/app_service/app_launch_params.h"
 #include "chrome/browser/apps/launch_service/launch_service.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h"
 #include "chrome/browser/chromeos/extensions/external_cache.h"
diff --git a/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager_browsertest.cc b/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager_browsertest.cc
index 1bb5d08..df89f2b 100644
--- a/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager_browsertest.cc
@@ -16,6 +16,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/cloud_external_data_manager_base.h"
 #include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
diff --git a/chrome/browser/chromeos/policy/display_settings_handler.cc b/chrome/browser/chromeos/policy/display_settings_handler.cc
index 61e79a4..607ddf8 100644
--- a/chrome/browser/chromeos/policy/display_settings_handler.cc
+++ b/chrome/browser/chromeos/policy/display_settings_handler.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 #include "ash/public/mojom/constants.mojom.h"
+#include "ash/public/mojom/cros_display_config.mojom.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/location.h"
@@ -16,13 +17,15 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "content/public/browser/system_connector.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 namespace policy {
 
 DisplaySettingsHandler::DisplaySettingsHandler() {
-  content::GetSystemConnector()->BindInterface(ash::mojom::kServiceName,
-                                               &cros_display_config_);
+  content::GetSystemConnector()->Connect(
+      ash::mojom::kServiceName,
+      cros_display_config_.BindNewPipeAndPassReceiver());
 }
 
 DisplaySettingsHandler::~DisplaySettingsHandler() = default;
@@ -64,9 +67,10 @@
     std::vector<ash::mojom::DisplayUnitInfoPtr> info_list) {
   // Add this as an observer to the mojo service now that it is ready.
   // (We only care about changes that occur after we apply any changes below).
-  ash::mojom::CrosDisplayConfigObserverAssociatedPtrInfo ptr_info;
-  cros_display_config_observer_binding_.Bind(mojo::MakeRequest(&ptr_info));
-  cros_display_config_->AddObserver(std::move(ptr_info));
+  mojo::PendingAssociatedRemote<ash::mojom::CrosDisplayConfigObserver> observer;
+  cros_display_config_observer_receiver_.Bind(
+      observer.InitWithNewEndpointAndPassReceiver());
+  cros_display_config_->AddObserver(std::move(observer));
 
   ApplyChanges(std::move(info_list));
 }
diff --git a/chrome/browser/chromeos/policy/display_settings_handler.h b/chrome/browser/chromeos/policy/display_settings_handler.h
index 6a2102c..5c03883d 100644
--- a/chrome/browser/chromeos/policy/display_settings_handler.h
+++ b/chrome/browser/chromeos/policy/display_settings_handler.h
@@ -12,7 +12,8 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace policy {
 
@@ -94,10 +95,10 @@
 
   // Provides access to the current display configurations, both for reading and
   // updating.
-  ash::mojom::CrosDisplayConfigControllerPtr cros_display_config_;
+  mojo::Remote<ash::mojom::CrosDisplayConfigController> cros_display_config_;
   std::vector<std::unique_ptr<DisplaySettingsPolicyHandler>> handlers_;
-  mojo::AssociatedBinding<ash::mojom::CrosDisplayConfigObserver>
-      cros_display_config_observer_binding_{this};
+  mojo::AssociatedReceiver<ash::mojom::CrosDisplayConfigObserver>
+      cros_display_config_observer_receiver_{this};
   std::vector<std::unique_ptr<chromeos::CrosSettings::ObserverSubscription>>
       settings_observers_;
   bool started_ = false;
diff --git a/chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.cc b/chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.cc
new file mode 100644
index 0000000..166ce89
--- /dev/null
+++ b/chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.cc
@@ -0,0 +1,36 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/policy/device_policy_decoder_chromeos.h"
+#include "chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.pb.h"
+#include "components/policy/core/common/external_data_manager.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/policy_types.h"
+#include "testing/libfuzzer/proto/lpm_interface.h"
+
+namespace policy {
+
+DEFINE_PROTO_FUZZER(const PolicyFuzzerProto& proto) {
+  if (!proto.has_chrome_device_settings())
+    return;
+
+  const enterprise_management::ChromeDeviceSettingsProto&
+      chrome_device_settings = proto.chrome_device_settings();
+
+  base::WeakPtr<ExternalDataManager> data_manager;
+  PolicyMap policy_map;
+  DecodeDevicePolicy(chrome_device_settings, data_manager, &policy_map);
+
+  for (const auto& it : policy_map) {
+    const std::string& policy_name = it.first;
+    const PolicyMap::Entry& entry = it.second;
+    CHECK(entry.value) << "Policy " << policy_name << " has an empty value";
+    CHECK_EQ(entry.scope, POLICY_SCOPE_MACHINE)
+        << "Policy " << policy_name << " has not machine scope";
+  }
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.proto b/chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.proto
new file mode 100644
index 0000000..099f5a9d
--- /dev/null
+++ b/chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.proto
@@ -0,0 +1,15 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+syntax = "proto3";
+
+package policy;
+
+import "chrome_device_policy.proto";
+
+option optimize_for = LITE_RUNTIME;
+
+message PolicyFuzzerProto {
+  enterprise_management.ChromeDeviceSettingsProto chrome_device_settings = 1;
+}
diff --git a/chrome/browser/chromeos/policy/hostname_handler.cc b/chrome/browser/chromeos/policy/hostname_handler.cc
index 481c509..ae6b4a8 100644
--- a/chrome/browser/chromeos/policy/hostname_handler.cc
+++ b/chrome/browser/chromeos/policy/hostname_handler.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chromeos/network/device_state.h"
 #include "chromeos/network/network_handler.h"
diff --git a/chrome/browser/chromeos/policy/policy_cert_service_factory.cc b/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
index 1a97ce7..e14a7af 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
+++ b/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
@@ -6,6 +6,7 @@
 
 #include "base/memory/singleton.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_network_configuration_updater.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service.h"
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_fetch_status_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_fetch_status_job.cc
index d53db21..bdc697c 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_fetch_status_job.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_fetch_status_job.cc
@@ -11,6 +11,7 @@
 #include "base/syslog_logging.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/chromeos/policy/status_uploader.h"
diff --git a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc
index e8f408c..49e0ec0 100644
--- a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc
@@ -11,6 +11,7 @@
 #include "base/syslog_logging.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/chromeos/policy/status_uploader.h"
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc b/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc
index c721a75..e29bd27d 100644
--- a/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc
+++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc
@@ -818,8 +818,7 @@
     const TpmStatusFetcher& tpm_status_fetcher,
     const EMMCLifetimeFetcher& emmc_lifetime_fetcher,
     const StatefulPartitionInfoFetcher& stateful_partition_info_fetcher,
-    const CrosHealthdDataFetcher& cros_healthd_data_fetcher,
-    bool is_enterprise_reporting)
+    const CrosHealthdDataFetcher& cros_healthd_data_fetcher)
     : StatusCollector(provider,
                       chromeos::CrosSettings::Get(),
                       chromeos::PowerManagerClient::Get(),
@@ -834,8 +833,7 @@
       stateful_partition_info_fetcher_(stateful_partition_info_fetcher),
       cros_healthd_data_fetcher_(cros_healthd_data_fetcher),
       runtime_probe_(
-          chromeos::DBusThreadManager::Get()->GetRuntimeProbeClient()),
-      is_enterprise_reporting_(is_enterprise_reporting) {
+          chromeos::DBusThreadManager::Get()->GetRuntimeProbeClient()) {
   // protected fields of `StatusCollector`.
   max_stored_past_activity_interval_ = kMaxStoredPastActivityInterval;
   max_stored_future_activity_interval_ = kMaxStoredFutureActivityInterval;
@@ -943,17 +941,12 @@
   chromeos::tpm_util::GetTpmVersion(base::BindOnce(
       &DeviceStatusCollector::OnTpmVersion, weak_factory_.GetWeakPtr()));
 
-  // If doing enterprise device-level reporting, observe the list of users to be
-  // reported. Consumer reporting is enforced for the signed-in registered user
-  // therefore this preference is not observed.
-  if (is_enterprise_reporting_) {
-    pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
-    pref_change_registrar_->Init(pref_service_);
-    pref_change_registrar_->Add(
-        prefs::kReportingUsers,
-        base::BindRepeating(&DeviceStatusCollector::ReportingUsersChanged,
-                            weak_factory_.GetWeakPtr()));
-  }
+  pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
+  pref_change_registrar_->Init(pref_service_);
+  pref_change_registrar_->Add(
+      prefs::kReportingUsers,
+      base::BindRepeating(&DeviceStatusCollector::ReportingUsersChanged,
+                          weak_factory_.GetWeakPtr()));
 
   DCHECK(pref_service_->GetInitializationStatus() !=
          PrefService::INITIALIZATION_STATUS_WAITING);
@@ -1003,12 +996,8 @@
                                   &report_version_info_)) {
     report_version_info_ = true;
   }
-  if (!is_enterprise_reporting_) {
-    // Only report activity times for consumer if time limit is enabled.
-    report_activity_times_ =
-        base::FeatureList::IsEnabled(features::kUsageTimeLimitPolicy);
-  } else if (!cros_settings_->GetBoolean(chromeos::kReportDeviceActivityTimes,
-                                         &report_activity_times_)) {
+  if (!cros_settings_->GetBoolean(chromeos::kReportDeviceActivityTimes,
+                                  &report_activity_times_)) {
     report_activity_times_ = true;
   }
   if (!cros_settings_->GetBoolean(chromeos::kReportDeviceBootMode,
@@ -1019,21 +1008,18 @@
                                   &report_kiosk_session_status_)) {
     report_kiosk_session_status_ = true;
   }
-  // Network interfaces are reported for enterprise devices only by default.
   if (!cros_settings_->GetBoolean(chromeos::kReportDeviceNetworkInterfaces,
                                   &report_network_interfaces_)) {
-    report_network_interfaces_ = is_enterprise_reporting_;
+    report_network_interfaces_ = true;
   }
-  // Device users are reported for enterprise devices only by default.
   if (!cros_settings_->GetBoolean(chromeos::kReportDeviceUsers,
                                   &report_users_)) {
-    report_users_ = is_enterprise_reporting_;
+    report_users_ = true;
   }
-  // Hardware status is reported for enterprise devices only by default.
   const bool already_reporting_hardware_status = report_hardware_status_;
   if (!cros_settings_->GetBoolean(chromeos::kReportDeviceHardwareStatus,
                                   &report_hardware_status_)) {
-    report_hardware_status_ = is_enterprise_reporting_;
+    report_hardware_status_ = true;
   }
   if (!cros_settings_->GetBoolean(chromeos::kReportDevicePowerStatus,
                                   &report_power_status_)) {
@@ -1076,7 +1062,7 @@
 void DeviceStatusCollector::ProcessIdleState(ui::IdleState state) {
   // Do nothing if device activity reporting is disabled or if it's a child
   // account. Usage time for child accounts are calculated differently.
-  if (!report_activity_times_ || !is_enterprise_reporting_ ||
+  if (!report_activity_times_ ||
       user_manager::UserManager::Get()->IsLoggedInAsChildUser()) {
     return;
   }
@@ -1085,7 +1071,6 @@
 
   // For kiosk apps we report total uptime instead of active time.
   if (state == ui::IDLE_STATE_ACTIVE || IsKioskApp()) {
-    CHECK(is_enterprise_reporting_);
     std::string user_email = GetUserForActivityReporting();
     // If it's been too long since the last report, or if the activity is
     // negative (which can happen when the clock changes), assume a single
@@ -1468,8 +1453,7 @@
   // Report only affiliated users for enterprise reporting and signed-in user
   // for consumer reporting.
   std::string primary_user_email = primary_user->GetAccountId().GetUserEmail();
-  if (is_enterprise_reporting_ &&
-      !chromeos::ChromeUserManager::Get()->ShouldReportUser(
+  if (!chromeos::ChromeUserManager::Get()->ShouldReportUser(
           primary_user_email)) {
     return std::string();
   }
@@ -1477,10 +1461,9 @@
 }
 
 bool DeviceStatusCollector::IncludeEmailsInActivityReports() const {
-  // In enterprise reporting including users' emails depends on
-  // kReportDeviceUsers preference. In consumer reporting only current user is
-  // reported and email address is always included.
-  return !is_enterprise_reporting_ || report_users_;
+  // Including the users' email addresses in enterprise reporting depends on the
+  // |kReportDeviceUsers| preference.
+  return report_users_;
 }
 
 bool DeviceStatusCollector::GetActivityTimes(
@@ -1522,10 +1505,6 @@
 bool DeviceStatusCollector::GetVersionInfo(
     em::DeviceStatusReportRequest* status) {
   status->set_os_version(os_version_);
-  if (!is_enterprise_reporting_)
-    return true;
-
-  // Enterprise-only version reporting below.
   status->set_browser_version(version_info::GetVersionNumber());
   status->set_channel(ConvertToProtoChannel(chrome::GetChannel()));
   status->set_firmware_version(firmware_version_);
@@ -1989,13 +1968,6 @@
     status->set_user_dm_token(GetDMTokenForProfile(profile));
 
   // Time zone is not reported in enterprise reports.
-  if (!is_enterprise_reporting_) {
-    const std::string current_timezone =
-        base::UTF16ToUTF8(chromeos::system::TimezoneSettings::GetInstance()
-                              ->GetCurrentTimezoneID());
-    status->set_time_zone(current_timezone);
-    anything_reported_user = true;
-  }
 
   return anything_reported_user;
 }
@@ -2012,11 +1984,10 @@
   if (report_kiosk_session_status_)
     anything_reported |= GetKioskSessionStatus(status);
 
-  // Only report affiliated users' data in enterprise reporting and registered
-  // user data in consumer reporting. Note that device-local accounts are also
-  // affiliated. Currently we only report for the primary user.
-  if (primary_user &&
-      (!is_enterprise_reporting_ || primary_user->IsAffiliated())) {
+  // Only report affiliated users' data in enterprise reporting. Note that
+  // device-local accounts are also affiliated. Currently we only report for the
+  // primary user.
+  if (primary_user && primary_user->IsAffiliated()) {
     anything_reported |= GetSessionStatusForUser(state, status, primary_user);
   }
 
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector.h b/chrome/browser/chromeos/policy/status_collector/device_status_collector.h
index 17ccd93f..2454e117 100644
--- a/chrome/browser/chromeos/policy/status_collector/device_status_collector.h
+++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector.h
@@ -113,7 +113,7 @@
   DISALLOW_COPY_AND_ASSIGN(SampledData);
 };
 
-// Collects and summarizes the status of an enterprised-managed ChromeOS device.
+// Collects and summarizes the status of an enterprise-managed ChromeOS device.
 class DeviceStatusCollector : public StatusCollector,
                               public session_manager::SessionManagerObserver,
                               public chromeos::UsageTimeStateNotifier::Observer,
@@ -189,8 +189,7 @@
       const TpmStatusFetcher& tpm_status_fetcher,
       const EMMCLifetimeFetcher& emmc_lifetime_fetcher,
       const StatefulPartitionInfoFetcher& stateful_partition_info_fetcher,
-      const CrosHealthdDataFetcher& cros_healthd_data_fetcher,
-      bool is_enterprise_reporting);
+      const CrosHealthdDataFetcher& cros_healthd_data_fetcher);
   ~DeviceStatusCollector() override;
 
   // StatusCollector:
@@ -449,9 +448,6 @@
   bool report_storage_status_ = false;
   bool report_board_status_ = false;
 
-  // Whether reporting is for enterprise or consumer.
-  bool is_enterprise_reporting_ = false;
-
   std::unique_ptr<chromeos::CrosSettings::ObserverSubscription>
       activity_times_subscription_;
   std::unique_ptr<chromeos::CrosSettings::ObserverSubscription>
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
index 1c13501..a4e91cd 100644
--- a/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
+++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
@@ -155,8 +155,7 @@
       const policy::DeviceStatusCollector::StatefulPartitionInfoFetcher&
           stateful_partition_info_fetcher,
       const policy::DeviceStatusCollector::CrosHealthdDataFetcher&
-          cros_healthd_data_fetcher,
-      bool is_enterprise_device)
+          cros_healthd_data_fetcher)
       : policy::DeviceStatusCollector(pref_service,
                                       provider,
                                       volume_info_fetcher,
@@ -166,8 +165,7 @@
                                       tpm_status_fetcher,
                                       emmc_lifetime_fetcher,
                                       stateful_partition_info_fetcher,
-                                      cros_healthd_data_fetcher,
-                                      is_enterprise_device) {
+                                      cros_healthd_data_fetcher) {
     // Set the baseline time to a fixed value (1 hour after day start) to
     // prevent test flakiness due to a single activity period spanning two days.
     SetBaselineTime(Time::Now().LocalMidnight() + kHour);
@@ -588,7 +586,7 @@
         &local_state_, &fake_statistics_provider_, volume_info, cpu_stats,
         cpu_temp_fetcher, android_status_fetcher, tpm_status_fetcher,
         emmc_lifetime_fetcher, stateful_partition_info_fetcher,
-        cros_healthd_data_fetcher, true /* is_enterprise_device */);
+        cros_healthd_data_fetcher);
   }
 
   void GetStatus() {
diff --git a/chrome/browser/chromeos/policy/status_uploader_unittest.cc b/chrome/browser/chromeos/policy/status_uploader_unittest.cc
index 26ca669..ff1649b 100644
--- a/chrome/browser/chromeos/policy/status_uploader_unittest.cc
+++ b/chrome/browser/chromeos/policy/status_uploader_unittest.cc
@@ -65,8 +65,7 @@
             policy::DeviceStatusCollector::TpmStatusFetcher(),
             policy::DeviceStatusCollector::EMMCLifetimeFetcher(),
             policy::DeviceStatusCollector::StatefulPartitionInfoFetcher(),
-            policy::DeviceStatusCollector::CrosHealthdDataFetcher(),
-            true /* is_enterprise_device */) {}
+            policy::DeviceStatusCollector::CrosHealthdDataFetcher()) {}
 
   MOCK_METHOD1(GetStatusAsync, void(const policy::StatusCollectorCallback&));
 
diff --git a/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.cc b/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.cc
index cbc0368..d255c4e 100644
--- a/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.cc
+++ b/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.cc
@@ -11,6 +11,7 @@
 #include "base/timer/timer.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/tpm_firmware_update.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc b/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc
index 55ed098..95aa68f2 100644
--- a/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc
@@ -20,6 +20,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/active_directory_policy_manager.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/user_cloud_external_data_manager.h"
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
index 5db5518d..51893219 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
@@ -122,12 +122,12 @@
 
   // We do not record ALS value if lid is closed.
   if (*is_lid_closed_) {
-    VLOG(1) << "ALS ignored while lid-closed";
+    VLOG(1) << "ABAdapter ALS ignored while lid-closed";
     return;
   }
 
   if (now - lid_reopen_time_ < lid_open_delay_time_) {
-    VLOG(1) << "ALS ignored soon after lid-reopened";
+    VLOG(1) << "ABAdapter ALS ignored soon after lid-reopened";
     return;
   }
 
@@ -195,6 +195,13 @@
     const base::Optional<AlsAvgStdDev> log_als_avg_stddev =
         decision_at_first_recent_user_brightness_request->log_als_avg_stddev;
 
+    const std::string log_als =
+        log_als_avg_stddev ? base::StringPrintf("%.4f", log_als_avg_stddev->avg)
+                           : "";
+    VLOG(1) << "ABAdapter user brightness change: "
+            << "brightness=" << FormatToPrint(old_brightness_percent) << "->"
+            << FormatToPrint(new_brightness_percent) << " log_als=" << log_als;
+
     OnBrightnessChanged(
         *first_recent_user_brightness_request_time, new_brightness_percent,
         log_als_avg_stddev ? base::Optional<double>(log_als_avg_stddev->avg)
@@ -229,6 +236,13 @@
     model_iteration_count_at_user_brightness_change_ = model_.iteration_count;
   }
 
+  if (!adapter_disabled_by_user_adjustment_) {
+    // It's possible a new curve arrives after a user brighntess change disables
+    // the adapter, in that case we don't want to reset the |new_model_arrived_|
+    // because we could use this model after the adapter is re-enabled.
+    new_model_arrived_ = false;
+  }
+
   if (params_.user_adjustment_effect != UserAdjustmentEffect::kContinueAuto) {
     // Adapter will stop making brightness adjustment until suspend/resume or
     // when browser restarts.
@@ -244,6 +258,8 @@
 
   model_.personal_curve = brightness_curve;
   ++model_.iteration_count;
+  new_model_arrived_ = true;
+  VLOG(1) << "ABAdapter new model arrived";
 }
 
 void Adapter::OnModelInitialized(const Model& model) {
@@ -251,6 +267,7 @@
 
   model_initialized_ = true;
   model_ = model;
+  new_model_arrived_ = true;
 
   UpdateStatus();
 }
@@ -281,6 +298,9 @@
 
   if (params_.user_adjustment_effect == UserAdjustmentEffect::kPauseAuto)
     adapter_disabled_by_user_adjustment_ = false;
+
+  VLOG(1) << "ABAdapter suspend done with "
+          << (new_model_arrived_ ? "new" : "no new") << " model";
 }
 
 void Adapter::LidEventReceived(chromeos::PowerManagerClient::LidState state,
@@ -288,7 +308,7 @@
   is_lid_closed_ = state == chromeos::PowerManagerClient::LidState::CLOSED;
   if (!*is_lid_closed_) {
     lid_reopen_time_ = tick_clock_->NowTicks();
-    VLOG(1) << "Adapter received lid-reopened event";
+    VLOG(1) << "ABAdapter Adapter received lid-reopened event";
     return;
   }
 
@@ -397,16 +417,6 @@
       features::kAutoScreenBrightness, "stabilization_threshold",
       params_.stabilization_threshold);
 
-  const int model_curve_as_int = base::GetFieldTrialParamByFeatureAsInt(
-      features::kAutoScreenBrightness, "model_curve",
-      static_cast<int>(params_.model_curve));
-  if (model_curve_as_int < static_cast<int>(ModelCurve::kGlobal) ||
-      model_curve_as_int > static_cast<int>(ModelCurve::kMaxValue)) {
-    enabled_by_model_configs_ = false;
-    LogParameterError(ParameterError::kAdapterError);
-    return;
-  }
-  params_.model_curve = static_cast<ModelCurve>(model_curve_as_int);
   params_.auto_brightness_als_horizon = base::TimeDelta::FromSeconds(
       model_config.auto_brightness_als_horizon_seconds);
 
@@ -424,17 +434,10 @@
   params_.user_adjustment_effect =
       static_cast<UserAdjustmentEffect>(user_adjustment_effect_as_int);
 
-  params_.min_model_iteration_count = base::GetFieldTrialParamByFeatureAsInt(
-      features::kAutoScreenBrightness, "min_model_iteration_count",
-      params_.min_model_iteration_count);
-  if (params_.min_model_iteration_count <= 0) {
-    LogParameterError(ParameterError::kAdapterError);
-    enabled_by_model_configs_ = false;
-    return;
-  }
-
   UMA_HISTOGRAM_ENUMERATION("AutoScreenBrightness.UserAdjustmentEffect",
                             params_.user_adjustment_effect);
+  VLOG(1) << "ABAdapter user adjustment effect: "
+          << static_cast<int>(params_.user_adjustment_effect);
 }
 
 void Adapter::UpdateStatus() {
@@ -559,16 +562,8 @@
     return decision;
   }
 
-  if (params_.model_curve == ModelCurve::kPersonal && !model_.personal_curve) {
-    decision.no_brightness_change_cause =
-        NoBrightnessChangeCause::kMissingPersonalCurve;
-    return decision;
-  }
-
-  if (params_.model_curve == ModelCurve::kPersonal &&
-      model_.iteration_count < params_.min_model_iteration_count) {
-    decision.no_brightness_change_cause =
-        NoBrightnessChangeCause::kWaitingForTrainedPersonalCurve;
+  if (!new_model_arrived_) {
+    decision.no_brightness_change_cause = NoBrightnessChangeCause::kNoNewModel;
     return decision;
   }
 
@@ -661,10 +656,9 @@
   const double brightness = GetBrightnessBasedOnAmbientLogLux(log_als_avg);
   if (current_brightness_ &&
       std::abs(brightness - *current_brightness_) < kTol) {
-    VLOG(1) << "Model brightness change canceled: "
-            << "brightness="
-            << base::StringPrintf("%.4f", *current_brightness_) + "%->"
-            << base::StringPrintf("%.4f", brightness) << "%";
+    VLOG(1) << "ABAdapter model brightness change canceled: "
+            << "brightness=" << FormatToPrint(*current_brightness_) + "->"
+            << FormatToPrint(brightness);
     return;
   }
 
@@ -689,11 +683,9 @@
   UMA_HISTOGRAM_ENUMERATION("AutoScreenBrightness.BrightnessChange.Cause",
                             cause);
 
-  if (params_.model_curve == ModelCurve::kPersonal) {
-    UMA_HISTOGRAM_COUNTS_1000(
-        "AutoScreenBrightness.BrightnessChange.ModelIteration",
-        model_.iteration_count);
-  }
+  UMA_HISTOGRAM_COUNTS_1000(
+      "AutoScreenBrightness.BrightnessChange.ModelIteration",
+      model_.iteration_count);
 
   WriteLogMessages(log_als_avg, brightness, cause);
   model_brightness_change_counter_++;
@@ -704,18 +696,10 @@
 double Adapter::GetBrightnessBasedOnAmbientLogLux(
     double ambient_log_lux) const {
   DCHECK_EQ(adapter_status_, Status::kSuccess);
-  switch (params_.model_curve) {
-    case ModelCurve::kGlobal:
-      return model_.global_curve->Interpolate(ambient_log_lux);
-    case ModelCurve::kPersonal:
-      DCHECK(model_.personal_curve);
-      return model_.personal_curve->Interpolate(ambient_log_lux);
-    default:
-      // We use the latest curve available.
-      if (model_.personal_curve)
-        return model_.personal_curve->Interpolate(ambient_log_lux);
-      return model_.global_curve->Interpolate(ambient_log_lux);
-  }
+  // We use the latest curve available.
+  if (model_.personal_curve)
+    return model_.personal_curve->Interpolate(ambient_log_lux);
+  return model_.global_curve->Interpolate(ambient_log_lux);
 }
 
 void Adapter::OnBrightnessChanged(base::TimeTicks now,
@@ -753,14 +737,12 @@
           : "";
 
   const std::string old_brightness =
-      current_brightness_
-          ? base::StringPrintf("%.4f", current_brightness_.value()) + "%->"
-          : "";
+      current_brightness_ ? FormatToPrint(current_brightness_.value()) + "->"
+                          : "";
 
-  VLOG(1) << "Screen brightness change #" << model_brightness_change_counter_
-          << ": "
-          << "brightness=" << old_brightness
-          << base::StringPrintf("%.4f", new_brightness) << "%"
+  VLOG(1) << "ABAdapter screen brightness change #"
+          << model_brightness_change_counter_ << ": "
+          << "brightness=" << old_brightness << FormatToPrint(new_brightness)
           << " cause=" << BrightnessChangeCauseToString(cause)
           << " log_als=" << old_log_als
           << base::StringPrintf("%.4f", new_log_als);
@@ -858,11 +840,9 @@
   }
 
   // Log model iteration count.
-  if (params_.model_curve == ModelCurve::kPersonal) {
-    base::UmaHistogramCounts1000(
-        histogram_prefix + "ModelIteration",
-        model_iteration_count_at_user_brightness_change_);
-  }
+  base::UmaHistogramCounts1000(
+      histogram_prefix + "ModelIteration",
+      model_iteration_count_at_user_brightness_change_);
 }
 
 }  // namespace auto_screen_brightness
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h
index 1ffc05d..e0c9e83 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h
@@ -40,20 +40,6 @@
                 public ModelConfigLoader::Observer,
                 public PowerManagerClient::Observer {
  public:
-  // Type of curve to use.
-  // These values are persisted to logs. Entries should not be renumbered and
-  // numeric values should never be reused.
-  enum class ModelCurve {
-    // Always use the global curve.
-    kGlobal = 0,
-    // Always use the personal curve, and make no brightness adjustment until a
-    // personal curve is trained.
-    kPersonal = 1,
-    // Use the personal curve if available, else use the global curve.
-    kLatest = 2,
-    kMaxValue = kLatest
-  };
-
   // How user manual brightness change will affect Adapter.
   // These values are persisted to logs. Entries should not be renumbered and
   // numeric values should never be reused.
@@ -86,8 +72,6 @@
     double darkening_log_lux_threshold = 0.6;
     double stabilization_threshold = 0.15;
 
-    ModelCurve model_curve = ModelCurve::kLatest;
-
     // Average ambient value is calculated over the past
     // |auto_brightness_als_horizon|. This is only used for brightness update,
     // which can be different from the horizon used in model training.
@@ -98,10 +82,6 @@
         UserAdjustmentEffect::kPauseAuto;
 
     std::string metrics_key;
-
-    // If |model_curve| is |kPersonal| then we only use a personal curve if the
-    // the model has been trained at least |min_model_iteration_count|.
-    int min_model_iteration_count = 1;
   };
 
   // These values are persisted to logs. Entries should not be renumbered and
@@ -152,7 +132,8 @@
     // number of iterations.
     kWaitingForTrainedPersonalCurve = 9,
     kWaitingForReopenAls = 10,
-    kMaxValue = kWaitingForReopenAls
+    kNoNewModel = 11,
+    kMaxValue = kNoNewModel
   };
 
   struct AdapterDecision {
@@ -379,6 +360,13 @@
 
   Model model_;
 
+  // An indicator to tell Adapter whether a curve is available to use.
+  // It is set to false when a user changes brightness manually and the adapter
+  // isn't already disabled by a previous user adjustment.
+  // It is set to true when modeller is first initialized or when it exports a
+  // new curve.
+  bool new_model_arrived_ = false;
+
   // |average_log_ambient_lux_| is only recorded when screen brightness is
   // changed by either model or user. New thresholds will be calculated from it.
   base::Optional<double> average_log_ambient_lux_;
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc
index 3694a63..bdbcbf9 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc
@@ -302,7 +302,6 @@
       {"brightening_log_lux_threshold", "0.00001"},
       {"darkening_log_lux_threshold", "0.00001"},
       {"stabilization_threshold", "100000000"},
-      {"model_curve", "2"},
       {"user_adjustment_effect", "0"},
   };
 
@@ -655,10 +654,21 @@
   EXPECT_EQ(test_observer_.num_changes(), 0);
   CheckAvgLog({2, 4, 6, 8}, adapter_->GetCurrentAvgLogAlsForTesting().value());
 
-  // Another ALS reading is in and triggers brightness change.
+  // Another ALS reading is in but brightness isn't changed because there's no
+  // new curve.
   ForwardTimeAndReportAls({5});
+  EXPECT_EQ(test_observer_.num_changes(), 0);
+  CheckAvgLog({2, 4, 6, 8}, adapter_->GetCurrentAvgLogAlsForTesting().value());
+
+  // Another model comes in.
+  fake_modeller_.ReportModelTrained(*personal_curve_);
+  EXPECT_EQ(test_observer_.num_changes(), 0);
+  CheckAvgLog({2, 4, 6, 8}, adapter_->GetCurrentAvgLogAlsForTesting().value());
+
+  // Another ALS reading is in and brightness is changed this time.
+  ForwardTimeAndReportAls({15});
   EXPECT_EQ(test_observer_.num_changes(), 1);
-  CheckAvgLog({4, 6, 8, 2, 5},
+  CheckAvgLog({6, 8, 2, 5, 15},
               adapter_->GetCurrentAvgLogAlsForTesting().value());
 
   // Another user manual adjustment comes in.
@@ -669,7 +679,7 @@
   EXPECT_TRUE(adapter_->IsAppliedForTesting());
   histogram_tester_.ExpectUniqueSample(
       "AutoScreenBrightness.MissingAlsWhenBrightnessChanged", false, 3);
-  CheckAvgLog({6, 8, 2, 5}, adapter_->GetCurrentAvgLogAlsForTesting().value());
+  CheckAvgLog({8, 2, 5, 15}, adapter_->GetCurrentAvgLogAlsForTesting().value());
 }
 
 // Same as |UserBrightnessChangeAlsReadingExists| except that the 1st user
@@ -729,13 +739,12 @@
   EXPECT_TRUE(adapter_->IsAppliedForTesting());
   EXPECT_FALSE(adapter_->GetCurrentAvgLogAlsForTesting());
 
-  // ALS readings come in, and will trigger a brightness change.
+  // ALS readings come in, and will not trigger a brightness change because
+  // there is no new model.
   ForwardTimeAndReportAls({100});
   EXPECT_EQ(test_observer_.num_changes(), 0);
   ForwardTimeAndReportAls({101, 102, 103, 104});
-  EXPECT_EQ(test_observer_.num_changes(), 1);
-  CheckAvgLog({100, 101, 102, 103, 104},
-              adapter_->GetCurrentAvgLogAlsForTesting().value());
+  EXPECT_EQ(test_observer_.num_changes(), 0);
 
   // Another user manual adjustment comes in.
   task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
@@ -743,11 +752,9 @@
   histogram_tester_.ExpectBucketCount(
       "AutoScreenBrightness.MissingAlsWhenBrightnessChanged", true, 1);
   histogram_tester_.ExpectBucketCount(
-      "AutoScreenBrightness.MissingAlsWhenBrightnessChanged", false, 2);
+      "AutoScreenBrightness.MissingAlsWhenBrightnessChanged", false, 1);
   EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
   EXPECT_TRUE(adapter_->IsAppliedForTesting());
-  CheckAvgLog({101, 102, 103, 104},
-              adapter_->GetCurrentAvgLogAlsForTesting().value());
 }
 
 // Set |brightening_log_lux_threshold| to a very high value to effectively make
@@ -892,118 +899,10 @@
   CheckAvgLog({2}, adapter_->GetCurrentAvgLogAlsForTesting().value());
 }
 
-TEST_F(AdapterTest, UsePersonalCurve) {
-  std::map<std::string, std::string> params = default_params_;
-  params["model_curve"] = "1";
-
-  // Init modeller with only a global curve.
+TEST_F(AdapterTest, UseLatestCurve) {
   Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
-       Model(global_curve_, base::nullopt, 0), GetTestModelConfig(), params);
-
-  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
-
-  // Sufficient ALS data has come in but no brightness change is triggered
-  // because there is no personal curve.
-  ForwardTimeAndReportAls({1, 2, 3, 4, 5, 6, 7, 8});
-  EXPECT_EQ(test_observer_.num_changes(), 0);
-  EXPECT_EQ(adapter_->GetCurrentAvgLogAlsForTesting(), base::nullopt);
-
-  // Personal curve is received, it does not lead to any immediate brightness
-  // change.
-  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
-  fake_modeller_.ReportModelTrained(*personal_curve_);
-  EXPECT_EQ(test_observer_.num_changes(), 0);
-  EXPECT_EQ(adapter_->GetCurrentAvgLogAlsForTesting(), base::nullopt);
-
-  // Another ALS comes in, which triggers a brightness change.
-  ReportAls(20);
-  EXPECT_EQ(test_observer_.num_changes(), 1);
-  EXPECT_EQ(test_observer_.GetCause(),
-            power_manager::BacklightBrightnessChange_Cause_MODEL);
-
-  CheckAvgLog({5, 6, 7, 8, 20},
-              adapter_->GetCurrentAvgLogAlsForTesting().value());
-
-  // Brightness is changed according to the personal curve.
-  EXPECT_DOUBLE_EQ(test_observer_.GetBrightnessPercent(),
-                   personal_curve_->Interpolate(
-                       adapter_->GetCurrentAvgLogAlsForTesting().value()));
-}
-
-TEST_F(AdapterTest, UsePersonalCurveAfter3) {
-  std::map<std::string, std::string> params = default_params_;
-  params["model_curve"] = "1";
-  params["min_model_iteration_count"] = "3";
-
-  // Init modeller with only a global curve.
-  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
-       Model(global_curve_, base::nullopt, 0), GetTestModelConfig(), params);
-
-  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
-
-  // Sufficient ALS data has come in but no brightness change is triggered
-  // because there is no personal curve.
-  ForwardTimeAndReportAls({1, 2, 3, 4, 5, 6, 7, 8});
-  EXPECT_EQ(test_observer_.num_changes(), 0);
-  EXPECT_EQ(adapter_->GetCurrentAvgLogAlsForTesting(), base::nullopt);
-
-  // Personal curve is received, it does not lead to any immediate brightness
-  // change.
-  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
-  fake_modeller_.ReportModelTrained(*personal_curve_);
-  EXPECT_EQ(test_observer_.num_changes(), 0);
-  EXPECT_EQ(adapter_->GetCurrentAvgLogAlsForTesting(), base::nullopt);
-
-  // Another ALS comes in, which does not trigger a brightness change.
-  ReportAls(20);
-  EXPECT_EQ(test_observer_.num_changes(), 0);
-  EXPECT_EQ(adapter_->GetCurrentAvgLogAlsForTesting(), base::nullopt);
-
-  // Another training is done.
-  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
-  fake_modeller_.ReportModelTrained(*personal_curve_);
-  EXPECT_EQ(test_observer_.num_changes(), 0);
-  EXPECT_EQ(adapter_->GetCurrentAvgLogAlsForTesting(), base::nullopt);
-
-  // Another ALS comes in, which does not trigger a brightness change.
-  ReportAls(30);
-  EXPECT_EQ(test_observer_.num_changes(), 0);
-  EXPECT_EQ(adapter_->GetCurrentAvgLogAlsForTesting(), base::nullopt);
-
-  // Another training is done.
-  const base::Optional<MonotoneCubicSpline> personal_curve_2 =
-      MonotoneCubicSpline::CreateMonotoneCubicSpline({-4, 12, 20},
-                                                     {30, 60, 100});
-  DCHECK(personal_curve_2);
-
-  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
-  fake_modeller_.ReportModelTrained(*personal_curve_2);
-  EXPECT_EQ(test_observer_.num_changes(), 0);
-  EXPECT_EQ(adapter_->GetCurrentAvgLogAlsForTesting(), base::nullopt);
-
-  // Another ALS comes in, which triggers a brightness change.
-  ReportAls(40);
-  EXPECT_EQ(test_observer_.num_changes(), 1);
-  EXPECT_EQ(test_observer_.GetCause(),
-            power_manager::BacklightBrightnessChange_Cause_MODEL);
-
-  CheckAvgLog({7, 8, 20, 30, 40},
-              adapter_->GetCurrentAvgLogAlsForTesting().value());
-
-  // Brightness is changed according to the personal curve.
-  EXPECT_DOUBLE_EQ(test_observer_.GetBrightnessPercent(),
-                   personal_curve_2->Interpolate(
-                       adapter_->GetCurrentAvgLogAlsForTesting().value()));
-}
-
-TEST_F(AdapterTest, UseGlobalCurve) {
-  std::map<std::string, std::string> params = default_params_;
-  params["model_curve"] = "0";
-  // This param has no effect.
-  params["min_model_iteration_count"] = "3";
-
-  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
-       Model(global_curve_, personal_curve_, 0), GetTestModelConfig(), params);
+       Model(global_curve_, base::nullopt, 0), GetTestModelConfig(),
+       default_params_);
 
   EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
 
@@ -1025,9 +924,9 @@
   EXPECT_EQ(test_observer_.GetCause(),
             power_manager::BacklightBrightnessChange_Cause_MODEL);
 
-  // Brightness is changed according to the global curve.
+  // Brightness is changed according to the new personal curve.
   EXPECT_DOUBLE_EQ(test_observer_.GetBrightnessPercent(),
-                   global_curve_->Interpolate(
+                   personal_curve_->Interpolate(
                        adapter_->GetCurrentAvgLogAlsForTesting().value()));
 }
 
@@ -1084,45 +983,6 @@
   EXPECT_EQ(adapter_->GetCurrentAvgLogAlsForTesting(), base::nullopt);
 }
 
-TEST_F(AdapterTest, FeatureEnabledConfigEnabled) {
-  // Both feature flag and model config are enabled.
-  std::map<std::string, std::string> params = default_params_;
-  params["model_curve"] = "1";
-
-  // Init modeller with only a global curve.
-  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
-       Model(global_curve_, base::nullopt, 0), GetTestModelConfig(), params);
-
-  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
-
-  // Sufficient ALS data has come in but no brightness change is triggered
-  // because there is no personal curve.
-  ForwardTimeAndReportAls({1, 2, 3, 4, 5, 6, 7, 8});
-  EXPECT_EQ(test_observer_.num_changes(), 0);
-  EXPECT_EQ(adapter_->GetCurrentAvgLogAlsForTesting(), base::nullopt);
-
-  // Personal curve is received, it does not lead to any immediate brightness
-  // change.
-  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
-  fake_modeller_.ReportModelTrained(*personal_curve_);
-  EXPECT_EQ(test_observer_.num_changes(), 0);
-  EXPECT_EQ(adapter_->GetCurrentAvgLogAlsForTesting(), base::nullopt);
-
-  // Another ALS comes in, which triggers a brightness change.
-  ReportAls(20);
-  EXPECT_EQ(test_observer_.num_changes(), 1);
-  EXPECT_EQ(test_observer_.GetCause(),
-            power_manager::BacklightBrightnessChange_Cause_MODEL);
-
-  CheckAvgLog({5, 6, 7, 8, 20},
-              adapter_->GetCurrentAvgLogAlsForTesting().value());
-
-  // Brightness is changed according to the personal curve.
-  EXPECT_DOUBLE_EQ(test_observer_.GetBrightnessPercent(),
-                   personal_curve_->Interpolate(
-                       adapter_->GetCurrentAvgLogAlsForTesting().value()));
-}
-
 TEST_F(AdapterTest, ValidParameters) {
   Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
        Model(global_curve_, personal_curve_, 0), GetTestModelConfig(),
@@ -1166,6 +1026,7 @@
   EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
   EXPECT_FALSE(adapter_->IsAppliedForTesting());
 
+  fake_modeller_.ReportModelTrained(*personal_curve_);
   ForwardTimeAndReportAls({6, 7, 8, 9, 10, 11});
   EXPECT_EQ(test_observer_.num_changes(), 1);
   CheckAvgLog({1, 2, 3, 4, 5},
@@ -1213,20 +1074,29 @@
   CheckAvgLog({1, 2, 3, 4, 5},
               adapter_->GetCurrentAvgLogAlsForTesting().value());
 
-  // // SuspendDone is received, which reenables adapter.
+  // SuspendDone is received, which re-enables adapter.
   ReportSuspendDone();
   EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
   EXPECT_TRUE(adapter_->IsAppliedForTesting());
 
-  // Another ALS results in a brightness change.
+  // Another ALS comes in but brightness isn't changed because there's no new
+  // curve.
   ForwardTimeAndReportAls({109});
+  EXPECT_EQ(test_observer_.num_changes(), 1);
+  CheckAvgLog({1, 2, 3, 4, 5},
+              adapter_->GetCurrentAvgLogAlsForTesting().value());
+
+  // A new model is received.
+  fake_modeller_.ReportModelTrained(*personal_curve_);
+  EXPECT_EQ(test_observer_.num_changes(), 1);
+  ForwardTimeAndReportAls({110});
   EXPECT_EQ(test_observer_.num_changes(), 2);
-  CheckAvgLog({105, 106, 107, 108, 109},
+  CheckAvgLog({106, 107, 108, 109, 110},
               adapter_->GetCurrentAvgLogAlsForTesting().value());
 
   // Another user brightness change.
   ReportUserBrightnessChangeRequest(40.0, 50.0);
-  CheckAvgLog({105, 106, 107, 108, 109},
+  CheckAvgLog({106, 107, 108, 109, 110},
               adapter_->GetCurrentAvgLogAlsForTesting().value());
   EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
   EXPECT_FALSE(adapter_->IsAppliedForTesting());
@@ -1234,7 +1104,7 @@
   // New ALS data will not trigger brightness update.
   ForwardTimeAndReportAls({200});
   EXPECT_EQ(test_observer_.num_changes(), 2);
-  CheckAvgLog({105, 106, 107, 108, 109},
+  CheckAvgLog({106, 107, 108, 109, 110},
               adapter_->GetCurrentAvgLogAlsForTesting().value());
 
   // SuspendDone is received, which reenables adapter.
@@ -1242,10 +1112,13 @@
   EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
   EXPECT_TRUE(adapter_->IsAppliedForTesting());
 
+  // A new model is in.
+  fake_modeller_.ReportModelTrained(*personal_curve_);
+
   // Als readings come in but not sufficient time since user changed brightness.
   ForwardTimeAndReportAls({201, 202, 203});
   EXPECT_EQ(test_observer_.num_changes(), 2);
-  CheckAvgLog({105, 106, 107, 108, 109},
+  CheckAvgLog({106, 107, 108, 109, 110},
               adapter_->GetCurrentAvgLogAlsForTesting().value());
 
   ForwardTimeAndReportAls({204});
@@ -1288,8 +1161,8 @@
               adapter_->GetCurrentAvgLogAlsForTesting().value());
 
   ForwardTimeAndReportAls({104});
-  EXPECT_EQ(test_observer_.num_changes(), 2);
-  CheckAvgLog({100, 101, 102, 103, 104},
+  EXPECT_EQ(test_observer_.num_changes(), 1);
+  CheckAvgLog({2, 3, 4, 5, 10},
               adapter_->GetCurrentAvgLogAlsForTesting().value());
 }
 
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.cc b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.cc
index b0c1046e..f66eb54 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.cc
@@ -23,10 +23,6 @@
 
 namespace {
 
-// If the curve error is greater than |kErrorTol|, then error will be written
-// to logs.
-constexpr double kErrorTol = 5;
-
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
 // Logs whether a new brightness exceeded the reasonable distance from the old
@@ -140,6 +136,8 @@
       is_user);
   UMA_HISTOGRAM_ENUMERATION(
       "AutoScreenBrightness.ModelTraining.BrightnessChange", change);
+  VLOG(1) << "ABTrainer bounded brightness change type: "
+          << static_cast<int>(change);
 
   return base::ClampToRange(brightness_new, lower_bound, upper_bound) -
          brightness_old;
@@ -179,6 +177,9 @@
   // If model's prediction is consistent with user's selection, then no
   // brightness change will be necessary.
   if (is_consistent) {
+    VLOG(1) << "ABTrainer model user brightness consistent (model,user): "
+            << FormatToPrint(model_brightness - target_brightness) << ","
+            << FormatToPrint(bounded_user_adjustment);
     return 0.0;
   }
 
@@ -201,14 +202,21 @@
       std::string("AutoScreenBrightness.ModelTraining.Inaccuracy.") +
       (model_updated ? "Update" : "NoUpdate");
   base::UmaHistogramPercentage(histogram_name, std::round(error));
-  if (error > kErrorTol) {
-    VLOG(1) << "Model error " << (model_updated ? "with " : "without ")
-            << "model updated: " << base::StringPrintf("%.4f", error) << "%";
-  }
+  VLOG(1) << "ABTrainer model error " << (model_updated ? "with " : "without ")
+          << "model updated: " << FormatToPrint(error);
 }
 
 }  // namespace
 
+TrainingResult::TrainingResult() = default;
+TrainingResult::TrainingResult(
+    const base::Optional<MonotoneCubicSpline>& new_curve,
+    double error)
+    : new_curve(new_curve), error(error) {}
+
+TrainingResult::TrainingResult(const TrainingResult& result) = default;
+TrainingResult::~TrainingResult() = default;
+
 GaussianTrainer::Params::Params() = default;
 
 GaussianTrainer::GaussianTrainer() {
@@ -399,7 +407,7 @@
   return *current_curve_;
 }
 
-MonotoneCubicSpline GaussianTrainer::Train(
+TrainingResult GaussianTrainer::Train(
     const std::vector<TrainingDataPoint>& data) {
   DCHECK(global_curve_);
   DCHECK(current_curve_);
@@ -412,7 +420,7 @@
   if (!need_to_update_curve_) {
     const double error = CalculateCurveError(data);
     LogModelCurveError(error, false /* model_updated */);
-    return *current_curve_;
+    return TrainingResult(base::nullopt, error);
   }
 
   current_curve_ = MonotoneCubicSpline::CreateMonotoneCubicSpline(
@@ -422,7 +430,7 @@
 
   const double error = CalculateCurveError(data);
   LogModelCurveError(error, true /* model_updated */);
-  return *current_curve_;
+  return TrainingResult(current_curve_, error);
 }
 
 bool GaussianTrainer::IsInitialPersonalCurveValid() const {
@@ -454,6 +462,9 @@
                         is_brightness_outlier);
 
   if (is_brightness_outlier) {
+    VLOG(1) << "ABTrainer outlier (user,global): "
+            << FormatToPrint(data.brightness_old) << ","
+            << FormatToPrint(brightness_global);
     return;
   }
 
@@ -499,9 +510,11 @@
     const double max_value = brightness_[i] / min_ratios_[i - 1];
     brightness_[i - 1] =
         base::ClampToRange(brightness_[i - 1], min_value, max_value);
-    // TODO(jiameng): add UMA metrics.
-    if (brightness_[i - 1] > 100.0)
+    if (brightness_[i - 1] > 100.0) {
+      VLOG(1) << "ABTrainer exceeded max at " << (i - 1)
+              << " with value: " << FormatToPrint(brightness_[i - 1]);
       brightness_[i - 1] = 100.0;
+    }
   }
 
   // Updates control points to the right of |center_index| so that brightness
@@ -511,9 +524,11 @@
     const double max_value = brightness_[i] * max_ratios_[i];
     brightness_[i + 1] =
         base::ClampToRange(brightness_[i + 1], min_value, max_value);
-    // TODO(jiameng): add UMA metrics.
-    if (brightness_[i + 1] > 100.0)
+    if (brightness_[i + 1] > 100.0) {
+      VLOG(1) << "ABTrainer exceeded max at " << (i + 1)
+              << " with value: " << FormatToPrint(brightness_[i + 1]);
       brightness_[i + 1] = 100.0;
+    }
   }
 
 #ifndef NDEBUG
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.h b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.h
index 5a3a6af..d530bd4 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.h
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.h
@@ -13,6 +13,20 @@
 namespace power {
 namespace auto_screen_brightness {
 
+struct TrainingResult {
+  TrainingResult();
+  TrainingResult(const base::Optional<MonotoneCubicSpline>& new_curve,
+                 double error);
+  TrainingResult(const TrainingResult& result);
+  ~TrainingResult();
+  // |new_curve| will be nullopt if trainer's curve stays unchanged after
+  // training.
+  base::Optional<MonotoneCubicSpline> new_curve;
+  // Evaluation error of the latest curve (possibly updated) using the training
+  // data points.
+  double error;
+};
+
 // GaussianTrainer updates an existing brightness curve (a mapping from
 // ambient light to screen brightness) using training data points that represent
 // how user changes brightness following an ambient value change. The update
@@ -71,8 +85,7 @@
                         const MonotoneCubicSpline& current_curve) override;
   MonotoneCubicSpline GetGlobalCurve() const override;
   MonotoneCubicSpline GetCurrentCurve() const override;
-  MonotoneCubicSpline Train(
-      const std::vector<TrainingDataPoint>& data) override;
+  TrainingResult Train(const std::vector<TrainingDataPoint>& data) override;
 
  private:
   // Returns whether initial personal curve (passed in by |SetInitialCurves|) is
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer_unittest.cc
index 5e6b2fc..7a50aba5 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer_unittest.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer_unittest.cc
@@ -108,9 +108,9 @@
 
   // |data_too_low| and |data_too_high| are both ignored. Hence there is no
   // change in the personal curve.
-  const MonotoneCubicSpline trained_curve1 =
+  const TrainingResult result1 =
       gaussian_trainer_->Train({data_too_low, data_too_high});
-  EXPECT_EQ(trained_curve1, personal_curve_);
+  EXPECT_FALSE(result1.new_curve);
 
   // Next increase |brightness_bound_scale|, so that the two training data
   // points are no longer outliers. A new curve will be trained.
@@ -119,8 +119,10 @@
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_));
 
-  const MonotoneCubicSpline trained_curve2 =
+  const TrainingResult result2 =
       gaussian_trainer_->Train({data_too_low, data_too_high});
+  EXPECT_TRUE(result2.new_curve);
+  const MonotoneCubicSpline trained_curve2 = *result2.new_curve;
   EXPECT_FALSE(trained_curve2 == personal_curve_);
   const std::vector<double> new_log_lux2 = trained_curve2.GetControlPointsX();
 
@@ -153,9 +155,9 @@
 
   // |data_too_low| and |data_too_high| are both ignored. Hence there is no
   // change in the personal curve.
-  const MonotoneCubicSpline trained_curve1 =
+  const TrainingResult result1 =
       gaussian_trainer_->Train({data_too_low, data_too_high});
-  EXPECT_EQ(trained_curve1, personal_curve_);
+  EXPECT_FALSE(result1.new_curve);
 
   // Next increase |brightness_bound_offset|, so that the two training data
   // points are no longer outliers. A new curve will be trained.
@@ -164,8 +166,10 @@
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_));
 
-  const MonotoneCubicSpline trained_curve2 =
+  const TrainingResult result2 =
       gaussian_trainer_->Train({data_too_low, data_too_high});
+  EXPECT_TRUE(result2.new_curve);
+  const MonotoneCubicSpline trained_curve2 = *result2.new_curve;
   EXPECT_FALSE(trained_curve2 == personal_curve_);
   const std::vector<double> new_log_lux2 = trained_curve2.GetControlPointsX();
 
@@ -190,7 +194,8 @@
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_));
 
-  const MonotoneCubicSpline trained_curve1 = gaussian_trainer_->Train({data});
+  const MonotoneCubicSpline trained_curve1 =
+      *(gaussian_trainer_->Train({data}).new_curve);
   const std::vector<double> new_log_lux1 = trained_curve1.GetControlPointsX();
   const std::vector<double> new_brightness1 =
       trained_curve1.GetControlPointsY();
@@ -202,7 +207,8 @@
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_));
 
-  const MonotoneCubicSpline trained_curve2 = gaussian_trainer_->Train({data});
+  const MonotoneCubicSpline trained_curve2 =
+      *(gaussian_trainer_->Train({data}).new_curve);
   const std::vector<double> new_log_lux2 = trained_curve2.GetControlPointsX();
   const std::vector<double> new_brightness2 =
       trained_curve2.GetControlPointsY();
@@ -247,7 +253,8 @@
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_));
 
-  const MonotoneCubicSpline trained_curve1 = gaussian_trainer_->Train({data});
+  const MonotoneCubicSpline trained_curve1 =
+      *(gaussian_trainer_->Train({data}).new_curve);
   const std::vector<double> new_log_lux1 = trained_curve1.GetControlPointsX();
   const std::vector<double> new_brightness1 =
       trained_curve1.GetControlPointsY();
@@ -259,7 +266,8 @@
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_));
 
-  const MonotoneCubicSpline trained_curve2 = gaussian_trainer_->Train({data});
+  const MonotoneCubicSpline trained_curve2 =
+      *(gaussian_trainer_->Train({data}).new_curve);
   const std::vector<double> new_log_lux2 = trained_curve2.GetControlPointsX();
   const std::vector<double> new_brightness2 =
       trained_curve2.GetControlPointsY();
@@ -300,7 +308,8 @@
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_));
 
-  const MonotoneCubicSpline trained_curve1 = gaussian_trainer_->Train({data});
+  const MonotoneCubicSpline trained_curve1 =
+      *(gaussian_trainer_->Train({data}).new_curve);
   const std::vector<double> new_log_lux1 = trained_curve1.GetControlPointsX();
   const std::vector<double> new_brightness1 =
       trained_curve1.GetControlPointsY();
@@ -312,7 +321,8 @@
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_));
 
-  const MonotoneCubicSpline trained_curve2 = gaussian_trainer_->Train({data});
+  const MonotoneCubicSpline trained_curve2 =
+      *(gaussian_trainer_->Train({data}).new_curve);
   const std::vector<double> new_log_lux2 = trained_curve2.GetControlPointsX();
   const std::vector<double> new_brightness2 =
       trained_curve2.GetControlPointsY();
@@ -353,7 +363,8 @@
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_));
 
-  const MonotoneCubicSpline trained_curve1 = gaussian_trainer_->Train({data});
+  const MonotoneCubicSpline trained_curve1 =
+      *(gaussian_trainer_->Train({data}).new_curve);
   const std::vector<double> new_log_lux1 = trained_curve1.GetControlPointsX();
   const std::vector<double> new_brightness1 =
       trained_curve1.GetControlPointsY();
@@ -365,7 +376,8 @@
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_));
 
-  const MonotoneCubicSpline trained_curve2 = gaussian_trainer_->Train({data});
+  const MonotoneCubicSpline trained_curve2 =
+      *(gaussian_trainer_->Train({data}).new_curve);
   const std::vector<double> new_log_lux2 = trained_curve2.GetControlPointsX();
   const std::vector<double> new_brightness2 =
       trained_curve2.GetControlPointsY();
@@ -409,7 +421,8 @@
   ResetModelWithParams(params);
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, global_curve_));
-  const MonotoneCubicSpline trained_curve1 = gaussian_trainer_->Train({data});
+  const MonotoneCubicSpline trained_curve1 =
+      *(gaussian_trainer_->Train({data}).new_curve);
   const std::vector<double> new_log_lux1 = trained_curve1.GetControlPointsX();
   const std::vector<double> new_brightness1 =
       trained_curve1.GetControlPointsY();
@@ -420,7 +433,8 @@
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, global_curve_));
 
-  const MonotoneCubicSpline trained_curve2 = gaussian_trainer_->Train({data});
+  const MonotoneCubicSpline trained_curve2 =
+      *(gaussian_trainer_->Train({data}).new_curve);
   const std::vector<double> new_log_lux2 = trained_curve2.GetControlPointsX();
   const std::vector<double> new_brightness2 =
       trained_curve2.GetControlPointsY();
@@ -463,7 +477,8 @@
   ResetModelWithParams(params);
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, global_curve_));
-  const MonotoneCubicSpline trained_curve1 = gaussian_trainer_->Train({data});
+  const MonotoneCubicSpline trained_curve1 =
+      *(gaussian_trainer_->Train({data}).new_curve);
   const std::vector<double> new_log_lux1 = trained_curve1.GetControlPointsX();
   const std::vector<double> new_brightness1 =
       trained_curve1.GetControlPointsY();
@@ -474,7 +489,8 @@
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, global_curve_));
 
-  const MonotoneCubicSpline trained_curve2 = gaussian_trainer_->Train({data});
+  const MonotoneCubicSpline trained_curve2 =
+      *(gaussian_trainer_->Train({data}).new_curve);
   const std::vector<double> new_log_lux2 = trained_curve2.GetControlPointsX();
   const std::vector<double> new_brightness2 =
       trained_curve2.GetControlPointsY();
@@ -512,10 +528,11 @@
 
   // User increased brightness and target is lower than model prediction. Hence
   // no change to the curve.
-  EXPECT_EQ(gaussian_trainer_->Train(
-                {{ref_personal_brightness_ - 20, ref_personal_brightness_ - 10,
-                  ref_log_lux_, tick_clock_.NowTicks()}}),
-            personal_curve_);
+  EXPECT_FALSE(gaussian_trainer_
+                   ->Train({{ref_personal_brightness_ - 20,
+                             ref_personal_brightness_ - 10, ref_log_lux_,
+                             tick_clock_.NowTicks()}})
+                   .new_curve);
 
   ResetModelWithParams(default_params_);
   EXPECT_TRUE(
@@ -523,10 +540,11 @@
 
   // User decreased brightness and target is higher than model prediction. Hence
   // no change to the curve.
-  EXPECT_EQ(gaussian_trainer_->Train(
-                {{ref_personal_brightness_ + 20, ref_personal_brightness_ + 10,
-                  ref_log_lux_, tick_clock_.NowTicks()}}),
-            personal_curve_);
+  EXPECT_FALSE(gaussian_trainer_
+                   ->Train({{ref_personal_brightness_ + 20,
+                             ref_personal_brightness_ + 10, ref_log_lux_,
+                             tick_clock_.NowTicks()}})
+                   .new_curve);
 }
 
 // Tests numerical results of a trained curve so that we could detect any
@@ -554,7 +572,8 @@
   EXPECT_TRUE(
       gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_));
 
-  const MonotoneCubicSpline trained_curve = gaussian_trainer_->Train({data});
+  const MonotoneCubicSpline trained_curve =
+      *(gaussian_trainer_->Train({data}).new_curve);
   const base::Optional<MonotoneCubicSpline> expected_curve =
       MonotoneCubicSpline::CreateMonotoneCubicSpline(
           log_lux_, {3.0,   8.0,   12.48, 18.72, 24.96, 31.2, 37.44,
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc
index b67c38b..c35e91f 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc
@@ -21,6 +21,7 @@
 #include "base/task_runner_util.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/time.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/events/event.h"
@@ -53,6 +54,7 @@
 
 void LogModelLoadingStatus(ModelLoadingStatus status) {
   UMA_HISTOGRAM_ENUMERATION("AutoScreenBrightness.ModelLoadingStatus", status);
+  VLOG(1) << "ABModel model loading status: " << static_cast<int>(status);
 }
 
 // Loads saved model from locations specified by |spec|. This
@@ -123,9 +125,9 @@
 // and a latest curve.
 // This should run in another thread to be non-blocking to the main
 // thread (if |is_testing| is false).
-MonotoneCubicSpline TrainModel(Trainer* trainer,
-                               const std::vector<TrainingDataPoint>& data,
-                               bool is_testing) {
+TrainingResult TrainModel(Trainer* trainer,
+                          const std::vector<TrainingDataPoint>& data,
+                          bool is_testing) {
   DCHECK(is_testing ||
          !content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   return trainer->Train(data);
@@ -351,11 +353,11 @@
 
   const base::FilePath model_dir = profile_path.Append(kModelDir);
   if (!base::DirectoryExists(model_dir) && !base::CreateDirectory(model_dir)) {
-    VLOG(1) << "Auto screen brightness model dir does not exist.";
+    VLOG(1) << "ABModel auto screen brightness model dir does not exist.";
     return model_saving_spec;
   }
 
-  VLOG(1) << "Auto screen brightness model dir: " << model_dir.value();
+  VLOG(1) << "ABModel auto screen brightness model dir: " << model_dir.value();
   model_saving_spec.global_curve = model_dir.Append(kGlobalCurveFileName);
   model_saving_spec.personal_curve = model_dir.Append(kPersonalCurveFileName);
   model_saving_spec.iteration_count =
@@ -488,6 +490,10 @@
     training_delay_ = base::TimeDelta::FromSeconds(training_delay_in_seconds);
   }
 
+  curve_error_tolerance_ = GetFieldTrialParamByFeatureAsDouble(
+      features::kAutoScreenBrightness, "curve_error_tolerance",
+      curve_error_tolerance_);
+
   return true;
 }
 
@@ -517,12 +523,14 @@
 
   model_ = model;
   if (!model_.global_curve || *model_.global_curve != *initial_global_curve_) {
-    // Reset the model.
+    // Reset the model and erase personal curve from |model_| if it exists.
     model_.global_curve = initial_global_curve_;
-    model_.personal_curve = base::nullopt;
-    model_.iteration_count = 0;
+    ErasePersonalCurve();
     global_curve_reset_ = true;
+    VLOG(1) << "ABModel global curve reset";
   }
+  UMA_HISTOGRAM_BOOLEAN("AutoScreenBrightness.GlobalCurveResetOnInitialization",
+                        global_curve_reset_);
 
   DCHECK(model_.global_curve);
   // Run SetInitialCurves calculations on background thread to avoid blocking UI
@@ -557,6 +565,8 @@
 
   UMA_HISTOGRAM_BOOLEAN("AutoScreenBrightness.PersonalCurveValid",
                         is_personal_curve_valid);
+  VLOG(1) << "ABModel initial personal curve valid: "
+          << is_personal_curve_valid;
 
   const bool has_loaded_and_valid_personal_curve =
       model_.personal_curve && is_personal_curve_valid;
@@ -567,8 +577,7 @@
                                              : *model_.global_curve));
 
   if (!has_loaded_and_valid_personal_curve) {
-    model_.personal_curve = base::nullopt;
-    model_.iteration_count = 0;
+    ErasePersonalCurve();
   } else if (model_.iteration_count == 0) {
     model_.iteration_count = 1;
   }
@@ -614,33 +623,45 @@
   data_cache_ = std::vector<TrainingDataPoint>();
 }
 
-void ModellerImpl::OnTrainingFinished(const MonotoneCubicSpline& curve) {
+void ModellerImpl::OnTrainingFinished(const TrainingResult& result) {
   const base::TimeTicks now = tick_clock_->NowTicks();
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  ++model_.iteration_count;
-  for (auto& observer : observers_)
-    observer.OnModelTrained(curve);
+  // Only export the curve if there's a new curve and the error is small.
+  // "Export" means we update personal curve in |model_| and notify observers.
+  const bool export_personal_curve = result.new_curve &&
+                                     result.error <= curve_error_tolerance_ &&
+                                     result.new_curve != model_.personal_curve;
 
-  // Save personal curve if it doesn't exist or has been updated.
-  const bool save_personal_curve =
-      !model_.personal_curve || *model_.personal_curve != curve;
+  if (export_personal_curve) {
+    ++model_.iteration_count;
+    model_.personal_curve = result.new_curve;
+    for (auto& observer : observers_)
+      observer.OnModelTrained(*result.new_curve);
+  }
+
+  VLOG(1) << "ABModel training finished (has_new_curve,error,updated): "
+          << result.new_curve.has_value() << ", " << FormatToPrint(result.error)
+          << ", " << export_personal_curve;
+
   const std::string histogram_name =
       std::string("AutoScreenBrightness.TrainingCompleteDuration.") +
-      (save_personal_curve ? "NewCurve" : "NoNewCurve");
+      (export_personal_curve ? "NewCurve" : "NoNewCurve");
   base::UmaHistogramTimes(histogram_name, now - training_start_.value());
 
-  if (save_personal_curve)
-    model_.personal_curve = curve;
-
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(), FROM_HERE,
       base::BindOnce(&SaveModelToDisk, model_saving_spec_, model_,
-                     global_curve_reset_, save_personal_curve, is_testing_),
+                     global_curve_reset_, export_personal_curve, is_testing_),
       base::BindOnce(&ModellerImpl::OnModelSavedToDisk,
                      weak_ptr_factory_.GetWeakPtr()));
 }
 
+void ModellerImpl::ErasePersonalCurve() {
+  model_.personal_curve = base::nullopt;
+  model_.iteration_count = 0;
+}
+
 }  // namespace auto_screen_brightness
 }  // namespace power
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h
index 7f88a3c..9955717 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h
@@ -20,10 +20,10 @@
 #include "chrome/browser/chromeos/power/auto_screen_brightness/als_reader.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/als_samples.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/model_config.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/model_config_loader.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/modeller.h"
-#include "chrome/browser/chromeos/power/auto_screen_brightness/trainer.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
 #include "chrome/browser/profiles/profile.h"
 #include "ui/base/user_activity/user_activity_detector.h"
@@ -186,8 +186,11 @@
   // |data_cache_|.
   void StartTraining();
 
-  // Called after training is complete with a new curve.
-  void OnTrainingFinished(const MonotoneCubicSpline& curve);
+  // Called after training is complete.
+  void OnTrainingFinished(const TrainingResult& result);
+
+  // Erase all info related to the personal curve.
+  void ErasePersonalCurve();
 
   // If |is_testing_| is false, we check curve saving/loading and training jobs
   // are running on non-UI thread.
@@ -204,6 +207,10 @@
   // This can be overridden by experiment flag "training_delay_in_seconds".
   base::TimeDelta training_delay_ = base::TimeDelta::FromSeconds(0);
 
+  // If personal curve error is above this threshold, the curve will not be
+  // exported. The error is expressed in terms of percentages.
+  double curve_error_tolerance_ = 5.0;
+
   ScopedObserver<AlsReader, AlsReader::Observer> als_reader_observer_;
 
   ScopedObserver<BrightnessMonitor, BrightnessMonitor::Observer>
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc
index 535c40a..818a5a27 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc
@@ -67,9 +67,14 @@
 // curve specified in the constructor.
 class FakeTrainer : public Trainer {
  public:
-  FakeTrainer(bool is_configured, bool is_personal_curve_valid)
+  FakeTrainer(bool is_configured,
+              bool is_personal_curve_valid,
+              bool return_new_curve,
+              double curve_error)
       : is_configured_(is_configured),
-        is_personal_curve_valid_(is_personal_curve_valid) {
+        is_personal_curve_valid_(is_personal_curve_valid),
+        return_new_curve_(return_new_curve),
+        curve_error_(curve_error) {
     // If personal curve is valid, then the trainer must be configured.
     DCHECK(!is_personal_curve_valid_ || is_configured_);
   }
@@ -98,8 +103,11 @@
     return *current_curve_;
   }
 
-  MonotoneCubicSpline Train(
-      const std::vector<TrainingDataPoint>& data) override {
+  TrainingResult Train(const std::vector<TrainingDataPoint>& data) override {
+    if (!return_new_curve_) {
+      return TrainingResult(base::nullopt, curve_error_);
+    }
+
     DCHECK(is_configured_);
     DCHECK(current_curve_);
     std::vector<TrainingDataPoint> used_data = data;
@@ -110,7 +118,7 @@
       used_data.push_back(data[0]);
     }
     current_curve_ = CreateTestCurveFromTrainingData(used_data);
-    return *current_curve_;
+    return TrainingResult(current_curve_, curve_error_);
   }
 
  private:
@@ -119,6 +127,9 @@
   base::Optional<MonotoneCubicSpline> global_curve_;
   base::Optional<MonotoneCubicSpline> current_curve_;
 
+  bool return_new_curve_ = false;
+  double curve_error_ = 0.0;
+
   DISALLOW_COPY_AND_ASSIGN(FakeTrainer);
 };
 
@@ -180,12 +191,16 @@
   }
 
   // Sets up |modeller_| with a FakeTrainer.
-  void SetUpModeller(bool is_trainer_configured, bool is_personal_curve_valid) {
+  void SetUpModeller(bool is_trainer_configured,
+                     bool is_personal_curve_valid,
+                     bool return_new_curve,
+                     double curve_error) {
     modeller_ = ModellerImpl::CreateForTesting(
         profile_.get(), &fake_als_reader_, &fake_brightness_monitor_,
         &fake_model_config_loader_, &user_activity_detector_,
         std::make_unique<FakeTrainer>(is_trainer_configured,
-                                      is_personal_curve_valid),
+                                      is_personal_curve_valid, return_new_curve,
+                                      curve_error),
         base::SequencedTaskRunnerHandle::Get(),
         task_environment_.GetMockTickClock());
 
@@ -198,6 +213,8 @@
             base::Optional<ModelConfig> model_config,
             bool is_trainer_configured = true,
             bool is_personal_curve_valid = true,
+            bool return_new_curve = true,
+            double curve_error = 0.0,
             const std::map<std::string, std::string>& params = {}) {
     if (!params.empty()) {
       scoped_feature_list_.InitAndEnableFeatureWithParameters(
@@ -210,7 +227,8 @@
       fake_model_config_loader_.set_model_config(model_config.value());
     }
 
-    SetUpModeller(is_trainer_configured, is_personal_curve_valid);
+    SetUpModeller(is_trainer_configured, is_personal_curve_valid,
+                  return_new_curve, curve_error);
     task_environment_.RunUntilIdle();
   }
 
@@ -497,7 +515,8 @@
 TEST_F(ModellerImplTest, OnUserBrightnessChanged) {
   Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
        test_model_config_, true /* is_trainer_configured */,
-       true /* is_personal_curve_valid */,
+       true /* is_personal_curve_valid */, true /* return_new_curve */,
+       0.0 /* curve_error */,
        {{"training_delay_in_seconds", base::NumberToString(60)}});
 
   const Model expected_model(test_initial_global_curve_, base::nullopt, 0);
@@ -552,7 +571,8 @@
 TEST_F(ModellerImplTest, MultipleUserActivities) {
   Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
        test_model_config_, true /* is_trainer_configured */,
-       true /* is_personal_curve_valid */,
+       true /* is_personal_curve_valid */, true /* return_new_curve */,
+       0.0 /* curve_error */,
        {{"training_delay_in_seconds", base::NumberToString(60)}});
 
   const Model expected_model(test_initial_global_curve_, base::nullopt, 0);
@@ -614,7 +634,8 @@
 TEST_F(ModellerImplTest, ZeroTrainingDelay) {
   Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
        test_model_config_, true /* is_trainer_configured */,
-       true /* is_personal_curve_valid  */,
+       true /* is_personal_curve_valid  */, true /* return_new_curve */,
+       0.0 /* curve_error */,
        {
            {"training_delay_in_seconds", "0"},
        });
@@ -633,6 +654,73 @@
   EXPECT_EQ(test_observer_->iteration_count(), 1);
 }
 
+// Curve is not updated and so model isn't exported.
+TEST_F(ModellerImplTest, CurveUnchanged) {
+  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
+       test_model_config_, true /* is_trainer_configured */,
+       true /* is_personal_curve_valid  */, false /* return_new_curve */,
+       0.0 /* curve_error */,
+       {
+           {"training_delay_in_seconds", "0"},
+       });
+
+  const Model expected_model(test_initial_global_curve_, base::nullopt, 0);
+  test_observer_->CheckStatus(true /* is_model_initialized */, expected_model);
+
+  fake_als_reader_.ReportAmbientLightUpdate(30);
+
+  modeller_->OnUserBrightnessChanged(10, 20);
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ(0u, modeller_->NumberTrainingDataPointsForTesting());
+  EXPECT_EQ(test_observer_->iteration_count(), 0);
+}
+
+// Curve is updated but error is above the threshold, hence model isn't
+// exported.
+TEST_F(ModellerImplTest, CurveChangedLargeError) {
+  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
+       test_model_config_, true /* is_trainer_configured */,
+       true /* is_personal_curve_valid  */, true /* return_new_curve */,
+       10.0 /* curve_error */,
+       {
+           {"training_delay_in_seconds", "0"},
+           {"curve_error_tolerance", "5"},
+       });
+
+  const Model expected_model(test_initial_global_curve_, base::nullopt, 0);
+  test_observer_->CheckStatus(true /* is_model_initialized */, expected_model);
+
+  fake_als_reader_.ReportAmbientLightUpdate(30);
+
+  modeller_->OnUserBrightnessChanged(10, 20);
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ(0u, modeller_->NumberTrainingDataPointsForTesting());
+  EXPECT_EQ(test_observer_->iteration_count(), 0);
+}
+
+// Curve is updated and error is not above the threshold, hence model is
+// exported.
+TEST_F(ModellerImplTest, CurveChangedSmallError) {
+  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
+       test_model_config_, true /* is_trainer_configured */,
+       true /* is_personal_curve_valid  */, true /* return_new_curve */,
+       10.0 /* curve_error */,
+       {
+           {"training_delay_in_seconds", "0"},
+           {"curve_error_tolerance", "10"},
+       });
+
+  const Model expected_model(test_initial_global_curve_, base::nullopt, 0);
+  test_observer_->CheckStatus(true /* is_model_initialized */, expected_model);
+
+  fake_als_reader_.ReportAmbientLightUpdate(30);
+  modeller_->OnUserBrightnessChanged(10, 20);
+  task_environment_.RunUntilIdle();
+
+  EXPECT_EQ(0u, modeller_->NumberTrainingDataPointsForTesting());
+  EXPECT_EQ(test_observer_->iteration_count(), 1);
+}
+
 }  // namespace auto_screen_brightness
 }  // namespace power
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/trainer.h b/chrome/browser/chromeos/power/auto_screen_brightness/trainer.h
index 594005c..0c6bf90 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/trainer.h
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/trainer.h
@@ -19,6 +19,8 @@
   base::TimeTicks sample_time;
 };
 
+struct TrainingResult;
+
 // Interface to train an on-device adaptive brightness curve.
 // User should call |HasValidConfiguration| first. If it returns true, then user
 // should call |SetInitialCurves| before calling other methods.
@@ -51,10 +53,10 @@
   // called.
   virtual MonotoneCubicSpline GetCurrentCurve() const = 0;
 
-  // Updates current curve stored in trainer with |data|. This function should
-  // only be called after |SetInitialCurves|.
-  virtual MonotoneCubicSpline Train(
-      const std::vector<TrainingDataPoint>& data) = 0;
+  // Possibly updates current curve stored in trainer with |data|, and returns
+  // training result.
+  // This function should only be called after |SetInitialCurves|.
+  virtual TrainingResult Train(const std::vector<TrainingDataPoint>& data) = 0;
 };
 
 }  // namespace auto_screen_brightness
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/utils.cc b/chrome/browser/chromeos/power/auto_screen_brightness/utils.cc
index cb3f016..9249515 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/utils.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/utils.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/strings/stringprintf.h"
 
 namespace chromeos {
 namespace power {
@@ -21,6 +22,10 @@
   return std::log(1 + value);
 }
 
+std::string FormatToPrint(double value) {
+  return base::StringPrintf("%.4f", value) + "%";
+}
+
 }  // namespace auto_screen_brightness
 }  // namespace power
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/utils.h b/chrome/browser/chromeos/power/auto_screen_brightness/utils.h
index 692a423..9859163 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/utils.h
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/utils.h
@@ -42,6 +42,9 @@
 // Logs to UMA that a parameter is invalid.
 void LogParameterError(ParameterError error);
 
+// Formats a double value that represents percentages.
+std::string FormatToPrint(double value);
+
 }  // namespace auto_screen_brightness
 }  // namespace power
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 7477548a..8f3d38c6 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -21,6 +21,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
 #include "chrome/browser/chromeos/base/locale_util.h"
@@ -128,8 +129,8 @@
   // |connector| may be null in tests.
   service_manager::Connector* connector = content::GetSystemConnector();
   if (connector) {
-    connector->BindInterface(ash::mojom::kServiceName,
-                             &cros_display_config_ptr_);
+    connector->Connect(ash::mojom::kServiceName,
+                       cros_display_config_.BindNewPipeAndPassReceiver());
   }
 }
 
@@ -753,8 +754,8 @@
       pref_name == prefs::kUnifiedDesktopEnabledByDefault) {
     // "Unified Desktop" is a per-user policy setting which will not be applied
     // until a user logs in.
-    if (cros_display_config_ptr_) {  // May be null in tests.
-      cros_display_config_ptr_->SetUnifiedDesktopEnabled(
+    if (cros_display_config_) {  // May be null in tests.
+      cros_display_config_->SetUnifiedDesktopEnabled(
           unified_desktop_enabled_by_default_.GetValue());
     }
   }
diff --git a/chrome/browser/chromeos/preferences.h b/chrome/browser/chromeos/preferences.h
index 54c3acf..3f00fa6 100644
--- a/chrome/browser/chromeos/preferences.h
+++ b/chrome/browser/chromeos/preferences.h
@@ -14,6 +14,7 @@
 #include "components/prefs/pref_member.h"
 #include "components/sync_preferences/pref_service_syncable_observer.h"
 #include "components/user_manager/user_manager.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
 
 class PrefRegistrySimple;
@@ -158,7 +159,7 @@
 
   std::unique_ptr<input_method::InputMethodSyncer> input_method_syncer_;
 
-  ash::mojom::CrosDisplayConfigControllerPtr cros_display_config_ptr_;
+  mojo::Remote<ash::mojom::CrosDisplayConfigController> cros_display_config_;
 
   DISALLOW_COPY_AND_ASSIGN(Preferences);
 };
diff --git a/chrome/browser/chromeos/printing/printer_configurer.cc b/chrome/browser/chromeos/printing/printer_configurer.cc
index 750a7d0..8fb572d 100644
--- a/chrome/browser/chromeos/printing/printer_configurer.cc
+++ b/chrome/browser/chromeos/printing/printer_configurer.cc
@@ -19,6 +19,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/printing/ppd_provider_factory.h"
 #include "chrome/browser/component_updater/cros_component_installer_chromeos.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/chromeos/profiles/profile_helper.cc b/chrome/browser/chromeos/profiles/profile_helper.cc
index cca3161..a1541e71 100644
--- a/chrome/browser/chromeos/profiles/profile_helper.cc
+++ b/chrome/browser/chromeos/profiles/profile_helper.cc
@@ -11,6 +11,7 @@
 #include "base/strings/string_util.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
 #include "chrome/browser/chromeos/base/file_flusher.h"
 #include "chrome/browser/chromeos/login/helper.h"
diff --git a/chrome/browser/chromeos/system/input_device_settings.cc b/chrome/browser/chromeos/system/input_device_settings.cc
index 413470d6..0811b677 100644
--- a/chrome/browser/chromeos/system/input_device_settings.cc
+++ b/chrome/browser/chromeos/system/input_device_settings.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/system/input_device_settings.h"
 
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
 #include "chromeos/system/statistics_provider.h"
diff --git a/chrome/browser/chromeos/system/timezone_resolver_manager.cc b/chrome/browser/chromeos/system/timezone_resolver_manager.cc
index f11d4b6..6bf89c29 100644
--- a/chrome/browser/chromeos/system/timezone_resolver_manager.cc
+++ b/chrome/browser/chromeos/system/timezone_resolver_manager.cc
@@ -8,6 +8,7 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/preferences.h"
 #include "chrome/browser/chromeos/system/input_device_settings.h"
 #include "chrome/browser/chromeos/system/timezone_util.h"
diff --git a/chrome/browser/chromeos/system/timezone_util.cc b/chrome/browser/chromeos/system/timezone_util.cc
index 78c4588..c5669d7 100644
--- a/chrome/browser/chromeos/system/timezone_util.cc
+++ b/chrome/browser/chromeos/system/timezone_util.cc
@@ -20,6 +20,7 @@
 #include "base/synchronization/lock.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
diff --git a/chrome/browser/chromeos/tpm_firmware_update.cc b/chrome/browser/chromeos/tpm_firmware_update.cc
index 4345eb1..b87e410 100644
--- a/chrome/browser/chromeos/tpm_firmware_update.cc
+++ b/chrome/browser/chromeos/tpm_firmware_update.cc
@@ -21,6 +21,7 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
diff --git a/chrome/browser/chromeos/ui/low_disk_notification.cc b/chrome/browser/chromeos/ui/low_disk_notification.cc
index 0c73cb5..b9d8e7b 100644
--- a/chrome/browser/chromeos/ui/low_disk_notification.cc
+++ b/chrome/browser/chromeos/ui/low_disk_notification.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/notifications/system_notification_helper.h"
 #include "chrome/browser/profiles/profile_manager.h"
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_measurement.cc b/chrome/browser/data_use_measurement/chrome_data_use_measurement.cc
index b04d5cd..df47a98 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_measurement.cc
+++ b/chrome/browser/data_use_measurement/chrome_data_use_measurement.cc
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 72c0f76..4bb0528 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -766,6 +766,7 @@
     "//components/safe_browsing/db:util",
     "//components/signin/core/browser",
     "//content/public/browser",
+    "//mojo/public/cpp/bindings",
   ]
   deps = [
     "//apps",
diff --git a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.cc b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.cc
index 87b1c700..60af1cb 100644
--- a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.cc
+++ b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.cc
@@ -7,6 +7,7 @@
 #include "base/values.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/extensions/api/identity/extension_token_key.cc b/chrome/browser/extensions/api/identity/extension_token_key.cc
index 08f81d0..351ec13 100644
--- a/chrome/browser/extensions/api/identity/extension_token_key.cc
+++ b/chrome/browser/extensions/api/identity/extension_token_key.cc
@@ -9,7 +9,7 @@
 namespace extensions {
 
 ExtensionTokenKey::ExtensionTokenKey(const std::string& extension_id,
-                                     const std::string& account_id,
+                                     const CoreAccountId& account_id,
                                      const std::set<std::string>& scopes)
     : extension_id(extension_id), account_id(account_id), scopes(scopes) {}
 
diff --git a/chrome/browser/extensions/api/identity/extension_token_key.h b/chrome/browser/extensions/api/identity/extension_token_key.h
index d722dee8..39c0a43 100644
--- a/chrome/browser/extensions/api/identity/extension_token_key.h
+++ b/chrome/browser/extensions/api/identity/extension_token_key.h
@@ -8,17 +8,19 @@
 #include <set>
 #include <string>
 
+#include "google_apis/gaia/core_account_id.h"
+
 namespace extensions {
 
 struct ExtensionTokenKey {
   ExtensionTokenKey(const std::string& extension_id,
-                    const std::string& account_id,
+                    const CoreAccountId& account_id,
                     const std::set<std::string>& scopes);
   ExtensionTokenKey(const ExtensionTokenKey& other);
   ~ExtensionTokenKey();
   bool operator<(const ExtensionTokenKey& rhs) const;
   std::string extension_id;
-  std::string account_id;
+  CoreAccountId account_id;
   std::set<std::string> scopes;
 };
 
diff --git a/chrome/browser/extensions/api/identity/extension_token_key_unittest.cc b/chrome/browser/extensions/api/identity/extension_token_key_unittest.cc
index aaedbd3b..cc2638bc 100644
--- a/chrome/browser/extensions/api/identity/extension_token_key_unittest.cc
+++ b/chrome/browser/extensions/api/identity/extension_token_key_unittest.cc
@@ -26,9 +26,9 @@
   extension_ids.push_back(extension_id1);
   extension_ids.push_back(extension_id2);
 
-  std::vector<std::string> user_ids;
-  user_ids.push_back("user_id_1");
-  user_ids.push_back("user_id_2");
+  std::vector<CoreAccountId> user_ids;
+  user_ids.push_back(CoreAccountId("user_id_1"));
+  user_ids.push_back(CoreAccountId("user_id_2"));
 
   std::vector<std::set<std::string> > scopesets;
   scopesets.push_back(scopes1);
@@ -40,7 +40,7 @@
       ExtensionTokenKeyIterator;
 
   std::vector<std::string>::const_iterator extension_it;
-  std::vector<std::string>::const_iterator user_it;
+  std::vector<CoreAccountId>::const_iterator user_it;
   std::vector<std::set<std::string> >::const_iterator scope_it;
 
   for (extension_it = extension_ids.begin();
diff --git a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
index 63053ca..f8677cb1 100644
--- a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
+++ b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
@@ -30,13 +30,9 @@
     : delegate_(delegate),
       profile_(profile),
       account_id_(token_key->account_id) {
-  TRACE_EVENT_ASYNC_BEGIN2("identity",
-                           "GaiaWebAuthFlow",
-                           this,
-                           "extension_id",
-                           token_key->extension_id,
-                           "account_id",
-                           token_key->account_id);
+  TRACE_EVENT_ASYNC_BEGIN2("identity", "GaiaWebAuthFlow", this, "extension_id",
+                           token_key->extension_id, "account_id",
+                           token_key->account_id.id);
 
   const char kOAuth2RedirectPathFormat[] = "/%s";
   const char kOAuth2AuthorizeFormat[] =
diff --git a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.h b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.h
index 8ba5fa6..037ac0c 100644
--- a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.h
+++ b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.h
@@ -89,7 +89,7 @@
 
   Delegate* delegate_;
   Profile* profile_;
-  std::string account_id_;
+  CoreAccountId account_id_;
   std::string redirect_scheme_;
   std::string redirect_path_prefix_;
   GURL auth_url_;
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc
index ef79b4e6..9a1ff1a 100644
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -485,7 +485,7 @@
 
  protected:
   // Returns the account ID of the created account.
-  std::string SignIn(const std::string& email) {
+  CoreAccountId SignIn(const std::string& email) {
     auto account_info = identity_test_env()->MakePrimaryAccountAvailable(email);
     return account_info.account_id;
   }
@@ -606,7 +606,7 @@
 
 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,
                        PrimaryAccountHasNoRefreshToken) {
-  std::string primary_account_id = SignIn("primary@example.com");
+  CoreAccountId primary_account_id = SignIn("primary@example.com");
   identity_test_env()->RemoveRefreshTokenForAccount(primary_account_id);
   EXPECT_TRUE(ExpectGetAccounts({}));
 }
@@ -776,7 +776,7 @@
     return ext;
   }
 
-  std::string GetPrimaryAccountId() {
+  CoreAccountId GetPrimaryAccountId() {
     return identity_test_env()->identity_manager()->GetPrimaryAccountId();
   }
 
@@ -785,13 +785,14 @@
     SetCachedTokenForAccount(GetPrimaryAccountId(), token_data);
   }
 
-  void SetCachedTokenForAccount(const std::string account_id,
+  void SetCachedTokenForAccount(const CoreAccountId account_id,
                                 const IdentityTokenCacheValue& token_data) {
     ExtensionTokenKey key(extension_id_, account_id, oauth_scopes_);
     id_api()->SetCachedToken(key, token_data);
   }
 
-  const IdentityTokenCacheValue& GetCachedToken(const std::string& account_id) {
+  const IdentityTokenCacheValue& GetCachedToken(
+      const CoreAccountId& account_id) {
     ExtensionTokenKey key(
         extension_id_, account_id.empty() ? GetPrimaryAccountId() : account_id,
         oauth_scopes_);
@@ -933,7 +934,7 @@
   EXPECT_FALSE(func->scope_ui_shown());
 
   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
-            GetCachedToken(std::string()).status());
+            GetCachedToken(CoreAccountId()).status());
 }
 
 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -1019,7 +1020,7 @@
   EXPECT_FALSE(func->login_ui_shown());
   EXPECT_FALSE(func->scope_ui_shown());
   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
-            GetCachedToken(std::string()).status());
+            GetCachedToken(CoreAccountId()).status());
 }
 
 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NonInteractiveSuccess) {
@@ -1036,7 +1037,7 @@
   EXPECT_FALSE(func->login_ui_shown());
   EXPECT_FALSE(func->scope_ui_shown());
   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
-            GetCachedToken(std::string()).status());
+            GetCachedToken(CoreAccountId()).status());
 }
 
 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveLoginCanceled) {
@@ -1310,7 +1311,7 @@
   EXPECT_TRUE(func->scope_ui_shown());
 
   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
-            GetCachedToken(std::string()).status());
+            GetCachedToken(CoreAccountId()).status());
 }
 
 #if !defined(OS_MACOSX)
@@ -1634,7 +1635,7 @@
   EXPECT_TRUE(func->login_ui_shown());
   EXPECT_TRUE(func->scope_ui_shown());
   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
-            GetCachedToken(std::string()).status());
+            GetCachedToken(CoreAccountId()).status());
 }
 #endif
 
@@ -1716,7 +1717,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ManuallyIssueToken) {
-  std::string primary_account_id = SignIn("primary@example.com");
+  CoreAccountId primary_account_id = SignIn("primary@example.com");
 
   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
@@ -1739,12 +1740,12 @@
   EXPECT_TRUE(value->GetAsString(&access_token));
   EXPECT_EQ(std::string(kAccessToken), access_token);
   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
-            GetCachedToken(std::string()).status());
+            GetCachedToken(CoreAccountId()).status());
   EXPECT_EQ(primary_account_access_token, func->login_access_token());
 }
 
 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ManuallyIssueTokenFailure) {
-  std::string primary_account_id = SignIn("primary@example.com");
+  CoreAccountId primary_account_id = SignIn("primary@example.com");
 
   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
   scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
@@ -1772,7 +1773,7 @@
 
 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
                        MultiDefaultUserManuallyIssueToken) {
-  std::string primary_account_id = SignIn("primary@example.com");
+  CoreAccountId primary_account_id = SignIn("primary@example.com");
   identity_test_env()->MakeAccountAvailable("secondary@example.com");
 
   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
@@ -1794,13 +1795,13 @@
   EXPECT_TRUE(value->GetAsString(&access_token));
   EXPECT_EQ(std::string(kAccessToken), access_token);
   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
-            GetCachedToken(std::string()).status());
+            GetCachedToken(CoreAccountId()).status());
   EXPECT_EQ(primary_account_access_token, func->login_access_token());
 }
 
 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
                        MultiPrimaryUserManuallyIssueToken) {
-  std::string primary_account_id = SignIn("primary@example.com");
+  CoreAccountId primary_account_id = SignIn("primary@example.com");
   identity_test_env()->MakeAccountAvailable("secondary@example.com");
 
   scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
@@ -1824,7 +1825,7 @@
   EXPECT_TRUE(value->GetAsString(&access_token));
   EXPECT_EQ(std::string(kAccessToken), access_token);
   EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
-            GetCachedToken(std::string()).status());
+            GetCachedToken(CoreAccountId()).status());
   EXPECT_EQ(primary_account_access_token, func->login_access_token());
 }
 
@@ -1834,8 +1835,8 @@
   if (id_api()->AreExtensionsRestrictedToPrimaryAccount())
     return;
 
-  std::string primary_account_id = SignIn("primary@example.com");
-  std::string secondary_account_id =
+  SignIn("primary@example.com");
+  CoreAccountId secondary_account_id =
       identity_test_env()
           ->MakeAccountAvailable("secondary@example.com")
           .account_id;
@@ -2141,14 +2142,15 @@
   }
 
   void SetCachedToken(const IdentityTokenCacheValue& token_data) {
-    ExtensionTokenKey key(kExtensionId, "test@example.com",
+    ExtensionTokenKey key(kExtensionId, CoreAccountId("test@example.com"),
                           std::set<std::string>());
     id_api()->SetCachedToken(key, token_data);
   }
 
   const IdentityTokenCacheValue& GetCachedToken() {
-    return id_api()->GetCachedToken(ExtensionTokenKey(
-        kExtensionId, "test@example.com", std::set<std::string>()));
+    return id_api()->GetCachedToken(
+        ExtensionTokenKey(kExtensionId, CoreAccountId("test@example.com"),
+                          std::set<std::string>()));
   }
 };
 
@@ -2450,7 +2452,7 @@
   account_info.id = "gaia_id_for_primary_example.com";
   AddExpectedEvent(api::identity::OnSignInChanged::Create(account_info, true));
 
-  std::string primary_account_id = SignIn("primary@example.com");
+  CoreAccountId primary_account_id = SignIn("primary@example.com");
 
   AddExpectedEvent(api::identity::OnSignInChanged::Create(account_info, false));
 
@@ -2468,7 +2470,7 @@
   account_info.id = "gaia_id_for_primary_example.com";
   AddExpectedEvent(api::identity::OnSignInChanged::Create(account_info, true));
 
-  std::string primary_account_id = SignIn("primary@example.com");
+  CoreAccountId primary_account_id = SignIn("primary@example.com");
 
   AddExpectedEvent(api::identity::OnSignInChanged::Create(account_info, false));
   identity_test_env()->RemoveRefreshTokenForAccount(primary_account_id);
diff --git a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
index 1de99c2..5ef4deb 100644
--- a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
+++ b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
@@ -14,6 +14,7 @@
 #include "base/task/post_task.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/extensions/api/identity/identity_api.h"
 #include "chrome/browser/extensions/api/identity/identity_constants.h"
 #include "chrome/browser/profiles/profile.h"
@@ -76,7 +77,7 @@
       should_prompt_for_scopes_(false),
       should_prompt_for_signin_(false),
       token_key_(/*extension_id=*/std::string(),
-                 /*account_id=*/std::string(),
+                 /*account_id=*/CoreAccountId(),
                  /*scopes=*/std::set<std::string>()),
       scoped_identity_manager_observer_(this) {
 }
@@ -205,7 +206,8 @@
 
 void IdentityGetAuthTokenFunction::OnReceivedExtensionAccountInfo(
     const CoreAccountInfo* account_info) {
-  token_key_.account_id = account_info ? account_info->account_id : "";
+  token_key_.account_id =
+      account_info ? account_info->account_id : CoreAccountId();
 
 #if defined(OS_CHROMEOS)
   policy::BrowserPolicyConnectorChromeOS* connector =
@@ -675,7 +677,7 @@
   if (access_token) {
     TRACE_EVENT_ASYNC_STEP_PAST1("identity", "IdentityGetAuthTokenFunction",
                                  this, "OnGetAccessTokenComplete", "account",
-                                 token_key_.account_id);
+                                 token_key_.account_id.id);
 
     StartGaiaRequest(access_token.value());
   } else {
diff --git a/chrome/browser/extensions/api/identity/identity_mint_queue_unittest.cc b/chrome/browser/extensions/api/identity/identity_mint_queue_unittest.cc
index 3dd5952..b77326d 100644
--- a/chrome/browser/extensions/api/identity/identity_mint_queue_unittest.cc
+++ b/chrome/browser/extensions/api/identity/identity_mint_queue_unittest.cc
@@ -22,8 +22,8 @@
 
 std::unique_ptr<ExtensionTokenKey> ExtensionIdToKey(
     const std::string& extension_id) {
-  return std::unique_ptr<ExtensionTokenKey>(
-      new ExtensionTokenKey(extension_id, "user_id", std::set<std::string>()));
+  return std::unique_ptr<ExtensionTokenKey>(new ExtensionTokenKey(
+      extension_id, CoreAccountId("user_id"), std::set<std::string>()));
 }
 
 }  // namespace
diff --git a/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.cc b/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.cc
index 69ddd3f..70f0710c 100644
--- a/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.cc
+++ b/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/component_updater/cros_component_installer_chromeos.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/chromeos/delegate_to_browser_gpu_service_accelerator_factory.h"
diff --git a/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_method_short.cc b/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_method_short.cc
index 65c4c99..18323cf 100644
--- a/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_method_short.cc
+++ b/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_method_short.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_method_short.h"
 
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/system/timezone_resolver_manager.h"
 #include "chrome/browser/extensions/api/settings_private/generated_pref.h"
 #include "chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.h"
diff --git a/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.cc b/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.cc
index 4227609b..3eec3a7e 100644
--- a/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.cc
+++ b/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.cc
@@ -6,6 +6,7 @@
 
 #include "base/feature_list.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/system/timezone_resolver_manager.h"
 #include "chrome/browser/extensions/api/settings_private/generated_pref.h"
 #include "chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.h"
diff --git a/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc b/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc
index 9e1dae7..92dd63b 100644
--- a/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc
+++ b/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc
@@ -6,6 +6,7 @@
 
 #include "base/feature_list.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/system/timezone_resolver_manager.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_features.h"
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 52f8e5f5..a4878a0 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -8,6 +8,7 @@
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/extensions/api/settings_private/generated_prefs.h"
 #include "chrome/browser/extensions/api/settings_private/generated_prefs_factory.h"
 #include "chrome/browser/extensions/chrome_extension_function.h"
diff --git a/chrome/browser/extensions/system_display/display_info_provider_chromeos.cc b/chrome/browser/extensions/system_display/display_info_provider_chromeos.cc
index babafca..cd55a8426 100644
--- a/chrome/browser/extensions/system_display/display_info_provider_chromeos.cc
+++ b/chrome/browser/extensions/system_display/display_info_provider_chromeos.cc
@@ -274,7 +274,8 @@
 DisplayInfoProviderChromeOS::DisplayInfoProviderChromeOS(
     service_manager::Connector* connector) {
   CHECK(connector);
-  connector->BindInterface(ash::mojom::kServiceName, &cros_display_config_);
+  connector->Connect(ash::mojom::kServiceName,
+                     cros_display_config_.BindNewPipeAndPassReceiver());
 }
 
 DisplayInfoProviderChromeOS::~DisplayInfoProviderChromeOS() = default;
diff --git a/chrome/browser/extensions/system_display/display_info_provider_chromeos.h b/chrome/browser/extensions/system_display/display_info_provider_chromeos.h
index 98b5ad1..03c0cc4 100644
--- a/chrome/browser/extensions/system_display/display_info_provider_chromeos.h
+++ b/chrome/browser/extensions/system_display/display_info_provider_chromeos.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "extensions/browser/api/system_display/display_info_provider.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace service_manager {
 class Connector;
@@ -74,7 +75,7 @@
                             ash::mojom::TouchCalibrationPtr calibration,
                             ErrorCallback callback);
 
-  ash::mojom::CrosDisplayConfigControllerPtr cros_display_config_;
+  mojo::Remote<ash::mojom::CrosDisplayConfigController> cros_display_config_;
   std::string touch_calibration_target_id_;
   base::WeakPtrFactory<DisplayInfoProviderChromeOS> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/extensions/system_display/display_info_provider_chromeos_unittest.cc b/chrome/browser/extensions/system_display/display_info_provider_chromeos_unittest.cc
index a601c21..7c0c202c 100644
--- a/chrome/browser/extensions/system_display/display_info_provider_chromeos_unittest.cc
+++ b/chrome/browser/extensions/system_display/display_info_provider_chromeos_unittest.cc
@@ -6,6 +6,8 @@
 
 #include <stdint.h>
 
+#include <utility>
+
 #include "ash/display/cros_display_config.h"
 #include "ash/display/screen_orientation_controller.h"
 #include "ash/display/screen_orientation_controller_test_api.h"
@@ -23,6 +25,7 @@
 #include "chrome/test/base/chrome_ash_test_base.h"
 #include "content/public/test/test_service_manager_context.h"
 #include "extensions/common/api/system_display.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/display/display.h"
 #include "ui/display/display_layout.h"
@@ -73,7 +76,7 @@
         service_manager::ServiceFilter::ByName(ash::mojom::kServiceName),
         ash::mojom::CrosDisplayConfigController::Name_,
         base::BindRepeating(&DisplayInfoProviderChromeosTest::
-                                AddCrosDisplayConfigControllerBinding,
+                                AddCrosDisplayConfigControllerReceiver,
                             base::Unretained(this)));
     // Provide the local connector to DisplayInfoProviderChromeOS.
     DisplayInfoProvider::InitializeForTesting(
@@ -85,10 +88,11 @@
     EXPECT_FALSE(ash::TabletMode::Get()->InTabletMode());
   }
 
-  void AddCrosDisplayConfigControllerBinding(
+  void AddCrosDisplayConfigControllerReceiver(
       mojo::ScopedMessagePipeHandle handle) {
-    cros_display_config_->BindRequest(
-        ash::mojom::CrosDisplayConfigControllerRequest(std::move(handle)));
+    cros_display_config_->BindReceiver(
+        mojo::PendingReceiver<ash::mojom::CrosDisplayConfigController>(
+            std::move(handle)));
   }
 
   float GetDisplayZoom(int64_t display_id) {
diff --git a/chrome/browser/extensions/user_script_listener.cc b/chrome/browser/extensions/user_script_listener.cc
index 3341190d..a91ff55f 100644
--- a/chrome/browser/extensions/user_script_listener.cc
+++ b/chrome/browser/extensions/user_script_listener.cc
@@ -15,6 +15,7 @@
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/navigation_throttle.h"
 #include "content/public/browser/notification_service.h"
+#include "content/public/common/resource_type.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest_handlers/content_scripts_handler.h"
 #include "extensions/common/url_pattern.h"
diff --git a/chrome/browser/external_protocol/external_protocol_handler.cc b/chrome/browser/external_protocol/external_protocol_handler.cc
index cf15d572..c4eafbf8 100644
--- a/chrome/browser/external_protocol/external_protocol_handler.cc
+++ b/chrome/browser/external_protocol/external_protocol_handler.cc
@@ -172,8 +172,8 @@
                           web_contents->GetBrowserContext(), escaped_url)) {
     // Handle tel links by opening the Click to Call dialog. This will call back
     // into LaunchUrlWithoutSecurityCheck if the user selects a system handler.
-    ClickToCallUiController::ShowDialog(web_contents, escaped_url,
-                                        chrome_is_default_handler);
+    ClickToCallUiController::ShowDialog(web_contents, initiating_origin,
+                                        escaped_url, chrome_is_default_handler);
     return;
   }
 #endif
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
index 86724d2..2d40012 100644
--- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
+++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
@@ -244,8 +244,9 @@
 ChromeInternalLogSource::ChromeInternalLogSource()
     : SystemLogsSource("ChromeInternal") {
 #if defined(OS_CHROMEOS)
-  content::GetSystemConnector()->BindInterface(ash::mojom::kServiceName,
-                                               &cros_display_config_ptr_);
+  content::GetSystemConnector()->Connect(
+      ash::mojom::kServiceName,
+      cros_display_config_.BindNewPipeAndPassReceiver());
 #endif
 }
 
@@ -297,7 +298,7 @@
 
   // Chain asynchronous fetchers: PopulateMonitorInfoAsync, PopulateEntriesAsync
   PopulateMonitorInfoAsync(
-      cros_display_config_ptr_.get(), response.get(),
+      cros_display_config_.get(), response.get(),
       base::BindOnce(
           [](std::unique_ptr<SystemLogsResponse> response,
              SysLogsSourceCallback callback) {
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h
index 79681f1..f73a1fad 100644
--- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h
+++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h
@@ -11,6 +11,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "ash/public/mojom/cros_display_config.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #endif
 
 namespace system_logs {
@@ -42,7 +43,7 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-  ash::mojom::CrosDisplayConfigControllerPtr cros_display_config_ptr_;
+  mojo::Remote<ash::mojom::CrosDisplayConfigController> cros_display_config_;
 #endif
 
   DISALLOW_COPY_AND_ASSIGN(ChromeInternalLogSource);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index c15ad7a..549e60a 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1616,11 +1616,6 @@
     "expiry_milestone": 80
   },
   {
-    "name": "enable-resource-load-scheduler",
-    "owners": [ "toyoshim" ],
-    "expiry_milestone": 78
-  },
-  {
     "name": "enable-resource-loading-hints",
     "owners": [ "//components/data_reduction_proxy/OWNERS" ],
     // This flag is used for frequent manual testing and should not be removed.
@@ -2262,7 +2257,7 @@
   {
     "name": "hardware-media-key-handling",
     "owners": [ "steimel", "media-dev" ],
-    "expiry_milestone": 77
+    "expiry_milestone": 84
   },
   {
     "name": "harfbuzz-pdf-subsetter",
@@ -2908,6 +2903,12 @@
     "expiry_milestone": 85
   },
   {
+    "name": "privacy-settings-redesign",
+    "owners": ["harrisonsean", "msramek",
+      "chrome-privacy-core@google.com"],
+    "expiry_milestone": 82
+  },
+  {
     "name": "proactive-tab-freeze",
     "owners": [ "fdoray" ],
     "expiry_milestone": 80
@@ -3414,7 +3415,7 @@
   {
     "name": "use-winrt-midi-api",
     "owners": [ "toyoshim" ],
-    "expiry_milestone": 76
+    "expiry_milestone": 83
   },
   {
     "name": "user-activation-v2",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 26ce2bb5..a51022b7 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1675,6 +1675,11 @@
 const char kPrintPreviewRegisterPromosDescription[] =
     "Enable registering unregistered cloud printers from print preview.";
 
+const char kPrivacySettingsRedesignName[] = "Privacy Settings Redesign";
+const char kPrivacySettingsRedesignDescription[] =
+    "Redesign of the privacy settings card to make it more prominent and "
+    "and easier to use.";
+
 const char kProminentDarkModeActiveTabTitleName[] =
     "Prominent Dark Mode Active Tab Titles";
 const char kProminentDarkModeActiveTabTitleDescription[] =
@@ -1737,11 +1742,6 @@
     "changed to indicate a tablet device. Web content optimized for tablets is "
     "received there after for the current tab.";
 
-const char kResourceLoadSchedulerName[] = "Enable resource load throttling";
-const char kResourceLoadSchedulerDescription[] =
-    "Uses the resource load scheduler in blink to throttle resource load "
-    "requests.";
-
 const char kPrefetchPrivacyChangesName[] =
     "Prefetch request properties are updated to be privacy-preserving";
 const char kPrefetchPrivacyChangesDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index c012cbc..ed8b9f9 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1000,6 +1000,9 @@
 extern const char kPrintPreviewRegisterPromosName[];
 extern const char kPrintPreviewRegisterPromosDescription[];
 
+extern const char kPrivacySettingsRedesignName[];
+extern const char kPrivacySettingsRedesignDescription[];
+
 extern const char kProminentDarkModeActiveTabTitleName[];
 extern const char kProminentDarkModeActiveTabTitleDescription[];
 
@@ -1034,9 +1037,6 @@
 extern const char kRequestTabletSiteName[];
 extern const char kRequestTabletSiteDescription[];
 
-extern const char kResourceLoadSchedulerName[];
-extern const char kResourceLoadSchedulerDescription[];
-
 extern const char kPrefetchPrivacyChangesName[];
 extern const char kPrefetchPrivacyChangesDescription[];
 
diff --git a/chrome/browser/fullscreen_aurax11.cc b/chrome/browser/fullscreen_aurax11.cc
index b186c00..10ac4a5 100644
--- a/chrome/browser/fullscreen_aurax11.cc
+++ b/chrome/browser/fullscreen_aurax11.cc
@@ -7,12 +7,12 @@
 #include <vector>
 
 #include "ui/gfx/native_widget_types.h"
-#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
 #include "ui/views/widget/widget.h"
 
 bool IsFullScreenMode() {
   std::vector<aura::Window*> all_windows =
-      views::DesktopWindowTreeHostX11::GetAllOpenWindows();
+      views::DesktopWindowTreeHostLinux::GetAllOpenWindows();
   // Only the topmost window is checked. This works fine in the most cases, but
   // it may return false when there are multiple displays and one display has
   // a fullscreen window but others don't. See: crbug.com/345484
diff --git a/chrome/browser/google/google_brand_chromeos.cc b/chrome/browser/google/google_brand_chromeos.cc
index 5128bd3..8d1cf6f 100644
--- a/chrome/browser/google/google_brand_chromeos.cc
+++ b/chrome/browser/google/google_brand_chromeos.cc
@@ -9,6 +9,7 @@
 #include "base/strings/string_util.h"
 #include "base/task/post_task.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/google/google_brand_code_map_chromeos.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/intranet_redirect_detector.cc b/chrome/browser/intranet_redirect_detector.cc
index 2495ed9..0fdad8e 100644
--- a/chrome/browser/intranet_redirect_detector.cc
+++ b/chrome/browser/intranet_redirect_detector.cc
@@ -222,21 +222,19 @@
 }
 
 void IntranetRedirectDetector::SetupDnsConfigClient() {
-  DCHECK(!dns_config_client_binding_.is_bound());
-
-  network::mojom::DnsConfigChangeManagerClientPtr client_ptr;
-  dns_config_client_binding_.Bind(mojo::MakeRequest(&client_ptr));
-  dns_config_client_binding_.set_connection_error_handler(base::BindRepeating(
-      &IntranetRedirectDetector::OnDnsConfigClientConnectionError,
-      base::Unretained(this)));
+  DCHECK(!dns_config_client_receiver_.is_bound());
 
   network::mojom::DnsConfigChangeManagerPtr manager_ptr;
   content::GetNetworkService()->GetDnsConfigChangeManager(
       mojo::MakeRequest(&manager_ptr));
-  manager_ptr->RequestNotifications(std::move(client_ptr));
+  manager_ptr->RequestNotifications(
+      dns_config_client_receiver_.BindNewPipeAndPassRemote());
+  dns_config_client_receiver_.set_disconnect_handler(base::BindRepeating(
+      &IntranetRedirectDetector::OnDnsConfigClientConnectionError,
+      base::Unretained(this)));
 }
 
 void IntranetRedirectDetector::OnDnsConfigClientConnectionError() {
-  dns_config_client_binding_.Close();
+  dns_config_client_receiver_.reset();
   SetupDnsConfigClient();
 }
diff --git a/chrome/browser/intranet_redirect_detector.h b/chrome/browser/intranet_redirect_detector.h
index fa2b4862..88e645b 100644
--- a/chrome/browser/intranet_redirect_detector.h
+++ b/chrome/browser/intranet_redirect_detector.h
@@ -14,7 +14,7 @@
 #include "base/memory/weak_ptr.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "services/network/public/cpp/network_connection_tracker.h"
 #include "services/network/public/mojom/host_resolver.mojom.h"
 #include "url/gurl.h"
@@ -90,8 +90,8 @@
                           // period that begins at browser start, or the
                           // one-second "no fetching" period that begins after
                           // network switches.
-  mojo::Binding<network::mojom::DnsConfigChangeManagerClient>
-      dns_config_client_binding_{this};
+  mojo::Receiver<network::mojom::DnsConfigChangeManagerClient>
+      dns_config_client_receiver_{this};
   base::WeakPtrFactory<IntranetRedirectDetector> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(IntranetRedirectDetector);
diff --git a/chrome/browser/invalidation/deprecated_profile_invalidation_provider_factory.cc b/chrome/browser/invalidation/deprecated_profile_invalidation_provider_factory.cc
index 2b910b6..67284b1c 100644
--- a/chrome/browser/invalidation/deprecated_profile_invalidation_provider_factory.cc
+++ b/chrome/browser/invalidation/deprecated_profile_invalidation_provider_factory.cc
@@ -11,6 +11,7 @@
 #include "base/task/post_task.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h"
diff --git a/chrome/browser/invalidation/profile_invalidation_provider_factory.cc b/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
index e01a21f..036c9b7 100644
--- a/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
+++ b/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/metrics/chromeos_metrics_provider.cc b/chrome/browser/metrics/chromeos_metrics_provider.cc
index 17bf3d0..e0d007b 100644
--- a/chrome/browser/metrics/chromeos_metrics_provider.cc
+++ b/chrome/browser/metrics/chromeos_metrics_provider.cc
@@ -22,6 +22,7 @@
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #include "chrome/browser/chromeos/arc/arc_optin_uma.h"
 #include "chrome/browser/chromeos/login/users/chrome_user_manager_util.h"
diff --git a/chrome/browser/net/cookie_policy_browsertest.cc b/chrome/browser/net/cookie_policy_browsertest.cc
index a647134..3729415 100644
--- a/chrome/browser/net/cookie_policy_browsertest.cc
+++ b/chrome/browser/net/cookie_policy_browsertest.cc
@@ -143,20 +143,6 @@
   DISALLOW_COPY_AND_ASSIGN(CookiePolicyBrowserTest);
 };
 
-// CookiePolicyBrowserTest with a feature list that enables usage of
-// TopLevelOrigin for CookieSettings. This is only required until this
-// behavior can be enabled by default. https://crbug.com/988398
-class CookiePolicyTopLevelOriginBrowserTest : public CookiePolicyBrowserTest {
- public:
-  CookiePolicyTopLevelOriginBrowserTest() {
-    enable_cookie_controls_.InitAndEnableFeature(
-        content_settings::kImprovedCookieControls);
-  }
-
- private:
-  base::test::ScopedFeatureList enable_cookie_controls_;
-};
-
 // Visits a page that sets a first-party cookie.
 IN_PROC_BROWSER_TEST_F(CookiePolicyBrowserTest, AllowFirstPartyCookies) {
   SetBlockThirdPartyCookies(false);
@@ -317,7 +303,7 @@
   ExpectNestedFrameContent("None");
 }
 
-IN_PROC_BROWSER_TEST_F(CookiePolicyTopLevelOriginBrowserTest,
+IN_PROC_BROWSER_TEST_F(CookiePolicyBrowserTest,
                        ThirdPartyCookiesIFrameExceptions) {
   SetBlockThirdPartyCookies(true);
 
@@ -354,7 +340,7 @@
   ExpectNestedFrameContent("thirdparty");
 }
 
-IN_PROC_BROWSER_TEST_F(CookiePolicyTopLevelOriginBrowserTest,
+IN_PROC_BROWSER_TEST_F(CookiePolicyBrowserTest,
                        ThirdPartyCookiesIFrameThirdPartyExceptions) {
   SetBlockThirdPartyCookies(true);
 
@@ -392,8 +378,7 @@
   ExpectNestedFrameContent("thirdparty");
 }
 
-IN_PROC_BROWSER_TEST_F(CookiePolicyTopLevelOriginBrowserTest,
-                       ThirdPartyIFrameStorage) {
+IN_PROC_BROWSER_TEST_F(CookiePolicyBrowserTest, ThirdPartyIFrameStorage) {
   NavigateToPageWithFrame("a.com");
   NavigateFrameTo("b.com", "/browsing_data/site_data.html");
   ExpectStorageForFrame(GetFrame(), false);
@@ -434,8 +419,7 @@
   ExpectStorageForFrame(GetFrame(), true);
 }
 
-IN_PROC_BROWSER_TEST_F(CookiePolicyTopLevelOriginBrowserTest,
-                       NestedThirdPartyIFrameStorage) {
+IN_PROC_BROWSER_TEST_F(CookiePolicyBrowserTest, NestedThirdPartyIFrameStorage) {
   NavigateToPageWithFrame("a.com");
   NavigateFrameTo("b.com", "/iframe.html");
   NavigateNestedFrameTo("c.com", "/browsing_data/site_data.html");
@@ -482,8 +466,7 @@
   ExpectStorageForFrame(GetNestedFrame(), true);
 }
 
-IN_PROC_BROWSER_TEST_F(CookiePolicyTopLevelOriginBrowserTest,
-                       NestedFirstPartyIFrameStorage) {
+IN_PROC_BROWSER_TEST_F(CookiePolicyBrowserTest, NestedFirstPartyIFrameStorage) {
   NavigateToPageWithFrame("a.com");
   NavigateFrameTo("b.com", "/iframe.html");
   NavigateNestedFrameTo("a.com", "/browsing_data/site_data.html");
diff --git a/chrome/browser/net/dns_probe_service_factory.cc b/chrome/browser/net/dns_probe_service_factory.cc
index 9fd02e2..dca6db2 100644
--- a/chrome/browser/net/dns_probe_service_factory.cc
+++ b/chrome/browser/net/dns_probe_service_factory.cc
@@ -22,7 +22,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/storage_partition.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
 #include "net/dns/public/dns_protocol.h"
@@ -169,7 +169,7 @@
 
   NetworkContextGetter network_context_getter_;
   DnsConfigChangeManagerGetter dns_config_change_manager_getter_;
-  mojo::Binding<network::mojom::DnsConfigChangeManagerClient> binding_;
+  mojo::Receiver<network::mojom::DnsConfigChangeManagerClient> receiver_{this};
   // DnsProbeRunners for the system DNS configuration and a public DNS server.
   DnsProbeRunner system_runner_;
   DnsProbeRunner public_runner_;
@@ -195,7 +195,6 @@
     : state_(STATE_NO_RESULT),
       network_context_getter_(network_context_getter),
       dns_config_change_manager_getter_(dns_config_change_manager_getter),
-      binding_(this),
       system_runner_(SystemOverrides(), network_context_getter),
       public_runner_(PublicOverrides(), network_context_getter),
       tick_clock_(tick_clock) {
@@ -315,13 +314,11 @@
 
 void DnsProbeServiceImpl::SetupDnsConfigChangeNotifications() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  network::mojom::DnsConfigChangeManagerClientPtr client_ptr;
-  binding_.Bind(mojo::MakeRequest(&client_ptr));
-  binding_.set_connection_error_handler(base::BindRepeating(
+  dns_config_change_manager_getter_.Run()->RequestNotifications(
+      receiver_.BindNewPipeAndPassRemote());
+  receiver_.set_disconnect_handler(base::BindRepeating(
       &DnsProbeServiceImpl::OnDnsConfigChangeManagerConnectionError,
       base::Unretained(this)));
-  dns_config_change_manager_getter_.Run()->RequestNotifications(
-      std::move(client_ptr));
 }
 
 void DnsProbeServiceImpl::OnDnsConfigChangeManagerConnectionError() {
@@ -330,7 +327,7 @@
   // getting notifications.
   ClearCachedResult();
 
-  binding_.Close();
+  receiver_.reset();
 
   SetupDnsConfigChangeNotifications();
 }
diff --git a/chrome/browser/net/dns_probe_test_util.cc b/chrome/browser/net/dns_probe_test_util.cc
index ac33e4b..103a8eaa 100644
--- a/chrome/browser/net/dns_probe_test_util.cc
+++ b/chrome/browser/net/dns_probe_test_util.cc
@@ -126,9 +126,9 @@
 FakeDnsConfigChangeManager::~FakeDnsConfigChangeManager() = default;
 
 void FakeDnsConfigChangeManager::RequestNotifications(
-    network::mojom::DnsConfigChangeManagerClientPtr client) {
+    mojo::PendingRemote<network::mojom::DnsConfigChangeManagerClient> client) {
   ASSERT_FALSE(client_);
-  client_ = std::move(client);
+  client_.Bind(std::move(client));
 }
 
 void FakeDnsConfigChangeManager::SimulateDnsConfigChange() {
diff --git a/chrome/browser/net/dns_probe_test_util.h b/chrome/browser/net/dns_probe_test_util.h
index f2fb5ed..b76859ba 100644
--- a/chrome/browser/net/dns_probe_test_util.h
+++ b/chrome/browser/net/dns_probe_test_util.h
@@ -109,13 +109,14 @@
 
   // mojom::DnsConfigChangeManager implementation:
   void RequestNotifications(
-      network::mojom::DnsConfigChangeManagerClientPtr client) override;
+      mojo::PendingRemote<network::mojom::DnsConfigChangeManagerClient> client)
+      override;
 
   void SimulateDnsConfigChange();
 
  private:
   mojo::Binding<network::mojom::DnsConfigChangeManager> binding_;
-  network::mojom::DnsConfigChangeManagerClientPtr client_;
+  mojo::Remote<network::mojom::DnsConfigChangeManagerClient> client_;
 };
 
 }  // namespace chrome_browser_net
diff --git a/chrome/browser/net/errorpage_browsertest.cc b/chrome/browser/net/errorpage_browsertest.cc
index a7c5fb0b..b4531e8 100644
--- a/chrome/browser/net/errorpage_browsertest.cc
+++ b/chrome/browser/net/errorpage_browsertest.cc
@@ -25,6 +25,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
 #include "chrome/browser/net/net_error_diagnostics_dialog.h"
diff --git a/chrome/browser/net/proxy_config_monitor.cc b/chrome/browser/net/proxy_config_monitor.cc
index f1e2875..2998cc0 100644
--- a/chrome/browser/net/proxy_config_monitor.cc
+++ b/chrome/browser/net/proxy_config_monitor.cc
@@ -14,6 +14,8 @@
 #include "components/proxy_config/pref_proxy_config_tracker_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "services/network/public/mojom/network_context.mojom.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -78,10 +80,10 @@
 
 void ProxyConfigMonitor::AddToNetworkContextParams(
     network::mojom::NetworkContextParams* network_context_params) {
-  network::mojom::ProxyConfigClientPtr proxy_config_client;
-  network_context_params->proxy_config_client_request =
-      mojo::MakeRequest(&proxy_config_client);
-  proxy_config_client_set_.AddPtr(std::move(proxy_config_client));
+  mojo::PendingRemote<network::mojom::ProxyConfigClient> proxy_config_client;
+  network_context_params->proxy_config_client_receiver =
+      proxy_config_client.InitWithNewPipeAndPassReceiver();
+  proxy_config_client_set_.Add(std::move(proxy_config_client));
 
   poller_binding_set_.AddBinding(
       this,
@@ -108,22 +110,20 @@
     net::ProxyConfigService::ConfigAvailability availability) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
          !BrowserThread::IsThreadInitialized(BrowserThread::UI));
-  proxy_config_client_set_.ForAllPtrs(
-      [config,
-       availability](network::mojom::ProxyConfigClient* proxy_config_client) {
-        switch (availability) {
-          case net::ProxyConfigService::CONFIG_VALID:
-            proxy_config_client->OnProxyConfigUpdated(config);
-            break;
-          case net::ProxyConfigService::CONFIG_UNSET:
-            proxy_config_client->OnProxyConfigUpdated(
-                net::ProxyConfigWithAnnotation::CreateDirect());
-            break;
-          case net::ProxyConfigService::CONFIG_PENDING:
-            NOTREACHED();
-            break;
-        }
-      });
+  for (const auto& proxy_config_client : proxy_config_client_set_) {
+    switch (availability) {
+      case net::ProxyConfigService::CONFIG_VALID:
+        proxy_config_client->OnProxyConfigUpdated(config);
+        break;
+      case net::ProxyConfigService::CONFIG_UNSET:
+        proxy_config_client->OnProxyConfigUpdated(
+            net::ProxyConfigWithAnnotation::CreateDirect());
+        break;
+      case net::ProxyConfigService::CONFIG_PENDING:
+        NOTREACHED();
+        break;
+    }
+  }
 }
 
 void ProxyConfigMonitor::OnLazyProxyConfigPoll() {
diff --git a/chrome/browser/net/proxy_config_monitor.h b/chrome/browser/net/proxy_config_monitor.h
index 0f20947..b0810fbc 100644
--- a/chrome/browser/net/proxy_config_monitor.h
+++ b/chrome/browser/net/proxy_config_monitor.h
@@ -12,7 +12,7 @@
 #include "build/buildflag.h"
 #include "extensions/buildflags/buildflags.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
 #include "net/proxy_resolution/proxy_config_service.h"
 #include "services/network/public/mojom/network_context.mojom-forward.h"
 #include "services/network/public/mojom/network_service.mojom-forward.h"
@@ -86,8 +86,7 @@
 
   mojo::BindingSet<network::mojom::ProxyConfigPollerClient> poller_binding_set_;
 
-  mojo::InterfacePtrSet<network::mojom::ProxyConfigClient>
-      proxy_config_client_set_;
+  mojo::RemoteSet<network::mojom::ProxyConfigClient> proxy_config_client_set_;
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   mojo::BindingSet<network::mojom::ProxyErrorClient> error_binding_set_;
diff --git a/chrome/browser/notifications/notification_platform_bridge_linux.cc b/chrome/browser/notifications/notification_platform_bridge_linux.cc
index 24bae810..3f38db507 100644
--- a/chrome/browser/notifications/notification_platform_bridge_linux.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_linux.cc
@@ -15,6 +15,7 @@
 
 #include "base/barrier_closure.h"
 #include "base/bind.h"
+#include "base/environment.h"
 #include "base/files/file_path_watcher.h"
 #include "base/files/file_util.h"
 #include "base/i18n/number_formatting.h"
diff --git a/chrome/browser/optimization_guide/prediction/prediction_manager.cc b/chrome/browser/optimization_guide/prediction/prediction_manager.cc
index 57a9690..bcabd411 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_manager.cc
+++ b/chrome/browser/optimization_guide/prediction/prediction_manager.cc
@@ -18,6 +18,7 @@
 #include "components/optimization_guide/optimization_guide_decider.h"
 #include "components/optimization_guide/optimization_guide_enums.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
 
 namespace optimization_guide {
 
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.cc b/chrome/browser/policy/cloud/user_policy_signin_service.cc
index 455e474..8f05e3ef 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service.cc
@@ -64,7 +64,7 @@
 
 void UserPolicySigninService::RegisterForPolicyWithAccountId(
     const std::string& username,
-    const std::string& account_id,
+    const CoreAccountId& account_id,
     const PolicyRegistrationCallback& callback) {
   DCHECK(!account_id.empty());
 
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.h b/chrome/browser/policy/cloud/user_policy_signin_service.h
index cd838c3..1678126 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service.h
+++ b/chrome/browser/policy/cloud/user_policy_signin_service.h
@@ -46,7 +46,7 @@
   // Virtual for testing.
   virtual void RegisterForPolicyWithAccountId(
       const std::string& username,
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       const PolicyRegistrationCallback& callback);
 
   // signin::IdentityManager::Observer implementation:
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index cf44c5a..eeb019c9 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -48,6 +48,7 @@
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/test/session_manager_state_waiter.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
diff --git a/chrome/browser/policy/policy_conversions.cc b/chrome/browser/policy/policy_conversions.cc
index 7489aa730..3846346 100644
--- a/chrome/browser/policy/policy_conversions.cc
+++ b/chrome/browser/policy/policy_conversions.cc
@@ -13,6 +13,7 @@
 #include "base/optional.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/policy/chrome_browser_policy_connector.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/policy/schema_registry_service.h"
diff --git a/chrome/browser/profiles/profile_downloader.cc b/chrome/browser/profiles/profile_downloader.cc
index 61b8235..bcf813f3 100644
--- a/chrome/browser/profiles/profile_downloader.cc
+++ b/chrome/browser/profiles/profile_downloader.cc
@@ -50,10 +50,10 @@
 }
 
 void ProfileDownloader::Start() {
-  StartForAccount(std::string());
+  StartForAccount(CoreAccountId());
 }
 
-void ProfileDownloader::StartForAccount(const std::string& account_id) {
+void ProfileDownloader::StartForAccount(const CoreAccountId& account_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   VLOG(1) << "Starting profile downloader...";
 
@@ -65,10 +65,8 @@
     return;
   }
 
-  // TODO(triploblastic@): Remove explicit conversion once ProfileDownloader
-  // has been fixed to use CoreAccountId.
   account_id_ = account_id.empty()
-                    ? identity_manager_->GetUnconsentedPrimaryAccountId().id
+                    ? identity_manager_->GetUnconsentedPrimaryAccountId()
                     : account_id;
   StartFetchingOAuth2AccessToken();
 }
diff --git a/chrome/browser/profiles/profile_downloader.h b/chrome/browser/profiles/profile_downloader.h
index 8f99d89..5a83589 100644
--- a/chrome/browser/profiles/profile_downloader.h
+++ b/chrome/browser/profiles/profile_downloader.h
@@ -50,7 +50,7 @@
   // Starts downloading profile information if the necessary authorization token
   // is ready. If not, subscribes to token service and starts fetching if the
   // token is available. Should not be called more than once.
-  virtual void StartForAccount(const std::string& account_id);
+  virtual void StartForAccount(const CoreAccountId& account_id);
 
   // On successful download this returns the hosted domain of the user.
   virtual base::string16 GetProfileHostedDomain() const;
@@ -116,7 +116,7 @@
   SEQUENCE_CHECKER(sequence_checker_);
 
   ProfileDownloaderDelegate* delegate_;
-  std::string account_id_;
+  CoreAccountId account_id_;
   std::string auth_token_;
   std::unique_ptr<network::SimpleURLLoader> simple_loader_;
   std::unique_ptr<signin::AccessTokenFetcher> oauth2_access_token_fetcher_;
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 2ecafc3..2326fea3 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -42,6 +42,7 @@
 #include "chrome/browser/background_sync/background_sync_controller_impl.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_factory.h"
 #include "chrome/browser/chrome_notification_types.h"
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index ab753f11..9bd35d8 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -830,12 +830,7 @@
     // twice when you highlight a link of the form <a
     // href="tel:+9876543210">+9876543210</a> and right click on it.
     MaybeAppendClickToCallItem();
-
-    // If this is a link, shared clipboard will be shown along with link items
-    // (AppendLinkItems), otherwise show it here beside the other sharing
-    // features.
-    if (params_.link_url.is_empty())
-      AppendSharedClipboardItems();
+    AppendSharedClipboardItems();
   }
   bool media_image = content_type_->SupportsGroup(
       ContextMenuContentType::ITEM_GROUP_MEDIA_IMAGE);
@@ -1271,14 +1266,11 @@
       }
     }
 #endif  // !defined(OS_CHROMEOS)
-    AppendSharedClipboardItems();
     if (browser && send_tab_to_self::ShouldOfferFeatureForLink(
                        active_web_contents, params_.link_url)) {
       send_tab_to_self::RecordSendTabToSelfClickResult(
           send_tab_to_self::kLinkMenu, SendTabToSelfClickResult::kShowItem);
-      // If Shared Clipboard is available don't add the separator.
-      if (!ShouldOfferSharedClipboard(browser_context_, params_.selection_text))
-        menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
+      menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
       if (send_tab_to_self::GetValidDeviceCount(GetBrowser()->profile()) == 1) {
 #if defined(OS_MACOSX)
         menu_model_.AddItem(IDC_CONTENT_LINK_SEND_TAB_TO_SELF_SINGLE_TARGET,
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc
index afea7e4..d97137f 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc
@@ -979,20 +979,20 @@
   // Do not freeze tabs that are casting/mirroring/playing audio.
   IsMediaTabImpl(decision_details);
 
-  if (GetStaticProactiveTabFreezeAndDiscardParams()
-          .should_protect_tabs_sharing_browsing_instance) {
-    if (web_contents()->GetSiteInstance()->GetRelatedActiveContentsCount() >
-        1U) {
-      decision_details->AddReason(
-          DecisionFailureReason::LIVE_STATE_SHARING_BROWSING_INSTANCE);
-    }
-  }
-
-  // Consult the local database to see if this tab could try to communicate with
-  // the user while in background (don't check for the visibility here as
-  // there's already a check for that above). Only do this for proactive
-  // interventions.
   if (intervention_type == InterventionType::kProactive) {
+    if (GetStaticProactiveTabFreezeAndDiscardParams()
+            .should_protect_tabs_sharing_browsing_instance) {
+      if (web_contents()->GetSiteInstance()->GetRelatedActiveContentsCount() >
+          1U) {
+        decision_details->AddReason(
+            DecisionFailureReason::LIVE_STATE_SHARING_BROWSING_INSTANCE);
+      }
+    }
+
+    // Consult the local database to see if this tab could try to communicate
+    // with the user while in background (don't check for the visibility here as
+    // there's already a check for that above). Only do this for proactive
+    // interventions.
     CheckIfTabCanCommunicateWithUserWhileInBackground(web_contents(),
                                                       decision_details);
   }
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.css b/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.css
index ef71aab..f200cdb 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.css
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.css
@@ -12,11 +12,12 @@
 }
 
 .oobe-popup {
-  width: 640px;
+  max-width: 640px;
 }
 
 #webview-container {
-  width: 100%;
+  box-sizing: border-box;
+  padding: 16px;
 }
 
 #webview-container.overlay-loading > webview,
@@ -33,8 +34,6 @@
 #overlay-webview-loading {
   display: block;
   height: 300px;
-  margin: 16px;
-  width: 608px;
 }
 
 #overlay-close-button {
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.html
index c5dc263..6fc21a8 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.html
@@ -31,10 +31,11 @@
     </oobe-dialog>
 
     <div id="third-party-overlay" class="popup-overlay" hidden>
-      <div id="overlay-container" class="oobe-popup not-resizable">
-        <div id="webview-container">
-          <webview id="overlay-webview"></webview>
-          <div id="overlay-webview-loading">
+      <div id="overlay-container" class="oobe-popup not-resizable layout
+          vertical">
+        <div id="webview-container" class="layout horizontal">
+          <webview id="overlay-webview" class="flex"></webview>
+          <div id="overlay-webview-loading" class="flex">
             <p i18n-content="assistantOobePopupOverlayLoading"></p>
           </div>
         </div>
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.css b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.css
index 95950d4..81c6a29f 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.css
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.css
@@ -13,18 +13,18 @@
 }
 
 #value-prop-container {
-  border-right: 1px solid rgb(218, 220, 224);
+  border-inline-end: 1px solid rgb(218, 220, 224);
   width: 50%;
 }
 
 #consents-container {
-  padding-left: 24px;
+  padding-inline-start: 24px;
   width: 50%;
 }
 
 #user-name {
   color: #757575;
-  padding-left: 8px;
+  padding-inline-start: 8px;
 }
 
 #footer-text {
@@ -40,7 +40,7 @@
 .oobe-popup {
   border-radius: 8px;
   box-shadow: unset;
-  width: 512px;
+  max-width: 512px;
 }
 
 #overlay-text {
@@ -63,7 +63,7 @@
 }
 
 #overlay-close-button {
-  margin-right: 0;
+  margin-inline-end: 0;
 }
 
 #close-button-text {
diff --git a/chrome/browser/resources/chromeos/camera/src/js/device/constraints_preferrer.js b/chrome/browser/resources/chromeos/camera/src/js/device/constraints_preferrer.js
index a3d1e88b..14e0f0b 100644
--- a/chrome/browser/resources/chromeos/camera/src/js/device/constraints_preferrer.js
+++ b/chrome/browser/resources/chromeos/camera/src/js/device/constraints_preferrer.js
@@ -133,10 +133,10 @@
     super(resolBroker, doReconfigureStream);
 
     /**
-     * Object saving information of supported constant fps. Each of its key as
-     * device id and value as an object mapping from resolution to all constant
-     * fps options supported by that resolution.
-     * @type {!Object<string, Object<Array<number>, Array<number>>>}
+     * Object saving information of device supported constant fps. Each of its
+     * key as device id and value as an object mapping from resolution to all
+     * constant fps options supported by that resolution.
+     * @type {!Object<string, !Object<!Array<number>, !Array<number>>>}
      * @private
      */
     this.constFpsInfo_ = {};
@@ -238,12 +238,12 @@
       }
       this.prefResolution_[deviceId] = {width, height};
 
-      const constFpses = cca.device.SUPPORTED_CONSTANT_FPS.filter(
-          (fps) => !!fpsRanges.find(
-              ([minFps, maxFps]) => minFps === fps && maxFps === fps));
+      const constFpses =
+          fpsRanges.filter(([minFps, maxFps]) => minFps === maxFps)
+              .map(([fps]) => fps);
       const fpsInfo = {};
-      for (const r of Object.keys(videoMaxFps).map((r) => r.toString())) {
-        fpsInfo[r] = constFpses.filter((fps) => fps <= videoMaxFps[r]);
+      for (const [resolution, maxFps] of Object.entries(videoMaxFps)) {
+        fpsInfo[resolution] = constFpses.filter((fps) => fps <= maxFps);
       }
       this.constFpsInfo_[deviceId] = fpsInfo;
     });
@@ -263,11 +263,11 @@
     this.resolBroker_.notifyVideoPrefResolChange(deviceId, width, height);
 
     const fps = stream.getVideoTracks()[0].getSettings().frameRate;
-    const availableFpses = this.constFpsInfo_[deviceId][[width, height]];
-    if (availableFpses.includes(fps)) {
-      this.setPreferredConstFps_(deviceId, width, height, fps);
-    }
-    cca.state.set('multi-fps', availableFpses.length > 1);
+    this.setPreferredConstFps_(deviceId, width, height, fps);
+    const supportedConstFpses =
+        this.constFpsInfo_[deviceId][[width, height]].filter(
+            (fps) => cca.device.SUPPORTED_CONSTANT_FPS.includes(fps));
+    cca.state.set('multi-fps', supportedConstFpses.length > 1);
   }
 
   /**
@@ -305,14 +305,21 @@
     // support multiple constant fps options. The resolution-fps tuple are
     // sorted by user preference of constant fps.
     const getFpses = (r) => {
-      let constFpses = [null];
-      if (this.constFpsInfo_[deviceId][r].includes(30)) {
-        if (this.constFpsInfo_[deviceId][r].includes(60)) {
-          const prefFps =
-              this.prefFpses_[deviceId] && this.prefFpses_[deviceId][r] || 30;
-          constFpses = prefFps == 30 ? [30, 60] : [60, 30];
-        } else {
-          constFpses = [30];
+      let constFpses;
+      const constFpsInfo = this.constFpsInfo_[deviceId][r];
+      // The higher constant fps will be ignored if constant 30 and 60 presented
+      // due to currently lack of UI support for toggling it.
+      if (constFpsInfo.includes(30) && constFpsInfo.includes(60)) {
+        const prefFps =
+            this.prefFpses_[deviceId] && this.prefFpses_[deviceId][r] || 30;
+        constFpses = prefFps == 30 ? [30, 60] : [60, 30];
+      } else {
+        constFpses = [null];
+        if (constFpsInfo.length > 0) {
+          const maxConstFps = Math.max(...constFpsInfo);
+          if (maxConstFps >= 30) {
+            constFpses.unshift(maxConstFps);
+          }
         }
       }
       return constFpses.map((fps) => [...r, fps]);
@@ -384,7 +391,6 @@
             (maxR, R) => (maxR[0] * maxR[1] < R[0] * R[1] ? R : maxR), [0, 0]);
       }
       this.prefResolution_[deviceId] = {width, height};
-      return [deviceId, width, height, photoResols];
     });
     cca.proxy.browserProxy.localStorageSet(
         {devicePhotoResolution: this.prefResolution_});
@@ -455,7 +461,6 @@
                                         audio: false,
                                         video: {
                                           deviceId: {exact: deviceId},
-                                          frameRate: {min: 24},
                                           width,
                                           height,
                                         },
diff --git a/chrome/browser/resources/chromeos/login/arc_terms_of_service.css b/chrome/browser/resources/chromeos/login/arc_terms_of_service.css
index f732a77..50c01a4 100644
--- a/chrome/browser/resources/chromeos/login/arc_terms_of_service.css
+++ b/chrome/browser/resources/chromeos/login/arc_terms_of_service.css
@@ -78,13 +78,8 @@
   font-weight: 600;
 }
 
-#arc-tos-dialog {
-  height: 640px;
-}
-
 #arc-tos-container {
   box-shadow: 0 -2px 2px -2px rgba(0, 0, 0, 0.14);
-  padding: -4px 0 0 0;
 }
 
 #arc-tos-container::-webkit-scrollbar {
@@ -93,19 +88,18 @@
 
 #arc-tos-view {
   display: block;
-  height: 10px;
+  height: 100%;
   margin: auto;
+  min-height: 40px;
   padding: 0;
-  width: 638px;
+  width: 100%;
 }
 
 #arc-tos-view-container {
   border: 1px solid #d9d9d9;
   box-sizing: border-box;
-  flex: auto;
   margin: 0;
   padding: 0;
-  width: 100%;
 }
 
 #arc-tos-back-button,
diff --git a/chrome/browser/resources/chromeos/login/arc_terms_of_service.html b/chrome/browser/resources/chromeos/login/arc_terms_of_service.html
index 35d655d1..f96ea524 100644
--- a/chrome/browser/resources/chromeos/login/arc_terms_of_service.html
+++ b/chrome/browser/resources/chromeos/login/arc_terms_of_service.html
@@ -18,7 +18,7 @@
       <div slot="subtitle" i18n-content="arcTermsOfServiceScreenDescription">
       </div>
       <div id="arc-tos-container" slot="footer" class="flex layout vertical">
-        <div id="arc-tos-view-container" class="arc-tos-content">
+        <div id="arc-tos-view-container" class="arc-tos-content flex">
           <webview id="arc-tos-view"></webview>
         </div>
         <div id="arc-policy-link" class="arc-tos-content">
diff --git a/chrome/browser/resources/chromeos/login/oobe_flex_layout.css b/chrome/browser/resources/chromeos/login/oobe_flex_layout.css
index 484abc4..e2bc08d 100644
--- a/chrome/browser/resources/chromeos/login/oobe_flex_layout.css
+++ b/chrome/browser/resources/chromeos/login/oobe_flex_layout.css
@@ -53,6 +53,10 @@
   align-items: flex-end;
 }
 
+.layout.stretch {
+  align-items: stretch;
+}
+
 /* alignment in main axis */
 
 .layout.start-justified {
diff --git a/chrome/browser/resources/chromeos/login/oobe_popup_overlay.css b/chrome/browser/resources/chromeos/login/oobe_popup_overlay.css
index 18fd51a8..2c59fee0 100644
--- a/chrome/browser/resources/chromeos/login/oobe_popup_overlay.css
+++ b/chrome/browser/resources/chromeos/login/oobe_popup_overlay.css
@@ -18,14 +18,17 @@
   z-index: 5;
 }
 
+/* please use oobe-popup inside a popup-overlay only */
 .oobe-popup {
   background: white;
   border: 1px solid rgb(188, 193, 208);
   border-radius: 2px;
   box-shadow: 0 5px 80px #505050;
+  flex: 1 1 auto;
+  max-width: 460px;
   min-height: 250px;
+  min-width: 50px;
   position: relative;
-  width: 460px;
   z-index: 10;
 }
 
diff --git a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.css b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.css
index 5faa926e..4bcfadc 100644
--- a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.css
+++ b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.css
@@ -2,13 +2,6 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
-#arc-tos {
-  /* To prevent appearing visual gap at the bottom for the some languages. */
-  height: 640px;
-  min-height: unset;
-  padding: unset;
-}
-
 #arc-tos .popup-overlay {
   background: rgba(0, 0, 0, .5);
 }
@@ -33,7 +26,7 @@
   border: 1px solid #d9d9d9;
   display: block;
   height: 300px;
-  width: 622px;
+  width: 100%;
 }
 
 #arc-tos-overlay-webview-container.overlay-loading > webview,
@@ -82,7 +75,7 @@
 }
 
 .arc-overlay-url .oobe-popup {
-  width: 640px;
+  max-width: 640px;
 }
 
 .arc-overlay-text #arc-tos-overlay-webview-container,
diff --git a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.html b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.html
index dfc97de..2ae64d2 100644
--- a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.html
+++ b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.html
@@ -1,5 +1,6 @@
 <link rel="stylesheet" href="chrome://resources/css/overlay.css">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="stylesheet" href="oobe_flex_layout.css">
 
 <div class="step right hidden arc-tos-loading" id="arc-tos"
     role="group" hidden>
@@ -7,9 +8,10 @@
 
   <div id="arc-tos-overlay" class="popup-overlay" hidden>
     <a href="#" id="arc-tos-overlay-start" class="arc-tos-invisible-link"></a>
-    <div id="arc-tos-overlay-container" class="oobe-popup not-resizable">
+    <div id="arc-tos-overlay-container" class="oobe-popup not-resizable flex
+        layout vertical stretch">
       <div id="arc-tos-overlay-close-top"
-          class="arc-tos-overlay-close-top arc-overlay-close-button">
+          class="arc-tos-overlay-close-top arc-overlay-close-button self-end">
       </div>
       <div id="arc-tos-overlay-webview-container">
         <webview id="arc-tos-overlay-webview"></webview>
diff --git a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js
index 9f5fc2e..56cadb8 100644
--- a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js
+++ b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js
@@ -156,9 +156,6 @@
       metrics.querySelector('#learn-more-link-metrics').onclick = function() {
         self.showLearnMoreOverlay(leanMoreStatisticsText);
       };
-      // For device owner set up, this may come after the page is loaded.
-      // Recaculate the ToS webview height.
-      this.updateTermViewHight_();
     },
 
     /**
@@ -297,50 +294,6 @@
     },
 
     /**
-     * Buttons in Oobe wizard's button strip.
-     * @type {array} Array of Buttons.
-     */
-    get buttons() {
-      var buttons = [];
-
-      var skipButton = this.ownerDocument.createElement('button');
-      skipButton.id = 'arc-tos-skip-button';
-      skipButton.disabled = this.classList.contains('arc-tos-loading');
-      skipButton.classList.add('preserve-disabled-state');
-      skipButton.textContent =
-          loadTimeData.getString('arcTermsOfServiceSkipButton');
-      skipButton.addEventListener('click', this.onSkip.bind(this));
-      buttons.push(skipButton);
-
-      var retryButton = this.ownerDocument.createElement('button');
-      retryButton.id = 'arc-tos-retry-button';
-      retryButton.textContent =
-          loadTimeData.getString('arcTermsOfServiceRetryButton');
-      retryButton.addEventListener('click', this.reloadPlayStoreToS.bind(this));
-      buttons.push(retryButton);
-
-      var nextButton = this.ownerDocument.createElement('button');
-      nextButton.id = 'arc-tos-next-button';
-      nextButton.disabled = this.classList.contains('arc-tos-loading');
-      nextButton.classList.add('preserve-disabled-state');
-      nextButton.textContent =
-          loadTimeData.getString('arcTermsOfServiceNextButton');
-      nextButton.addEventListener('click', this.onNext.bind(this));
-      buttons.push(nextButton);
-
-      var acceptButton = this.ownerDocument.createElement('button');
-      acceptButton.id = 'arc-tos-accept-button';
-      acceptButton.disabled = this.classList.contains('arc-tos-loading');
-      acceptButton.classList.add('preserve-disabled-state');
-      acceptButton.textContent =
-          loadTimeData.getString('arcTermsOfServiceAcceptButton');
-      acceptButton.addEventListener('click', this.onAccept.bind(this));
-      buttons.push(acceptButton);
-
-      return buttons;
-    },
-
-    /**
      * Handles Next button click.
      */
     onNext: function() {
@@ -351,7 +304,6 @@
       if (!isDemoModeSetup) {
         this.getElement_('arc-review-settings').hidden = false;
       }
-      this.getElement_('arc-tos-container').style.overflowY = 'auto';
       this.getElement_('arc-tos-container').scrollTop =
           this.getElement_('arc-tos-container').scrollHeight;
       this.getElement_('arc-tos-next-button').hidden = true;
@@ -578,31 +530,9 @@
       this.getElement_('arc-pai-service').hidden = true;
       this.getElement_('arc-google-service-confirmation').hidden = true;
       this.getElement_('arc-review-settings').hidden = true;
-      this.getElement_('arc-tos-container').style.overflow = 'hidden';
       this.getElement_('arc-tos-accept-button').hidden = true;
       this.getElement_('arc-tos-next-button').hidden = false;
       this.getElement_('arc-tos-next-button').focus();
-
-      this.updateTermViewHight_();
-    },
-
-    /**
-     * Updates ToS webview height.
-     *
-     * @private
-     */
-    updateTermViewHight_() {
-      var termsView = this.getElement_('arc-tos-view');
-      var termsViewContainer = this.getElement_('arc-tos-view-container');
-      var setTermsHeight = function() {
-        // Reset terms-view height in order to stabilize style computation.
-        // For some reason, child webview affects final result.
-        termsView.style.height = '0px';
-        var style = window.getComputedStyle(termsViewContainer, null);
-        var height = style.getPropertyValue('height');
-        termsView.style.height = height;
-      };
-      setTimeout(setTermsHeight, 0);
     },
 
     /**
@@ -643,10 +573,6 @@
       this.setLearnMoreHandlers_();
 
       this.hideOverlay();
-      // ToS content may be loaded before the page is shown. In that case,
-      // height of ToS webview is not correctly calculated. Recalculate the
-      // height here.
-      this.updateTermViewHight_();
       this.focusButton_();
 
       $('arc-tos-root').onBeforeShow();
@@ -682,7 +608,6 @@
       this.getElement_('arc-pai-service').hidden = true;
       this.getElement_('arc-google-service-confirmation').hidden = true;
       this.getElement_('arc-review-settings').hidden = true;
-      this.getElement_('arc-tos-container').style.overflowY = 'auto';
       this.getElement_('arc-tos-container').scrollTop =
           this.getElement_('arc-tos-container').scrollHeight;
       this.getElement_('arc-tos-next-button').hidden = false;
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager.cc b/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
index 695babb..2f60482 100644
--- a/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
+++ b/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
@@ -107,7 +107,8 @@
 void AdvancedProtectionStatusManager::OnExtendedAccountInfoRemoved(
     const AccountInfo& info) {
   // If user signed out primary account, cancel refresh.
-  std::string unconsented_primary_account_id = GetUnconsentedPrimaryAccountId();
+  CoreAccountId unconsented_primary_account_id =
+      GetUnconsentedPrimaryAccountId();
   if (!unconsented_primary_account_id.empty() &&
       unconsented_primary_account_id == info.account_id) {
     is_under_advanced_protection_ = false;
@@ -138,7 +139,7 @@
 }
 
 void AdvancedProtectionStatusManager::OnAccessTokenFetchComplete(
-    std::string account_id,
+    CoreAccountId account_id,
     GoogleServiceAuthError error,
     signin::AccessTokenInfo token_info) {
   DCHECK(access_token_fetcher_);
@@ -169,7 +170,8 @@
 void AdvancedProtectionStatusManager::RefreshAdvancedProtectionStatus() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  std::string unconsented_primary_account_id = GetUnconsentedPrimaryAccountId();
+  CoreAccountId unconsented_primary_account_id =
+      GetUnconsentedPrimaryAccountId();
   if (!identity_manager_ || unconsented_primary_account_id.empty())
     return;
 
@@ -230,11 +232,12 @@
 }
 
 void AdvancedProtectionStatusManager::OnGetIDToken(
-    const std::string& account_id,
+    const CoreAccountId& account_id,
     const std::string& id_token) {
   // Skips if the ID token is not for the primary account. Or user is no longer
   // signed in.
-  std::string unconsented_primary_account_id = GetUnconsentedPrimaryAccountId();
+  CoreAccountId unconsented_primary_account_id =
+      GetUnconsentedPrimaryAccountId();
   if (unconsented_primary_account_id.empty() ||
       account_id != unconsented_primary_account_id)
     return;
@@ -270,13 +273,10 @@
   MaybeRefreshOnStartUp();
 }
 
-std::string AdvancedProtectionStatusManager::GetUnconsentedPrimaryAccountId()
+CoreAccountId AdvancedProtectionStatusManager::GetUnconsentedPrimaryAccountId()
     const {
-  // TODO(triploblastic@): Remove explicit conversion once
-  // AdvancedProtectionStatusManager has been fixed to use CoreAccountId.
-  return identity_manager_
-             ? identity_manager_->GetUnconsentedPrimaryAccountId().id
-             : std::string();
+  return identity_manager_ ? identity_manager_->GetUnconsentedPrimaryAccountId()
+                           : CoreAccountId();
 }
 
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager.h b/chrome/browser/safe_browsing/advanced_protection_status_manager.h
index 021a909..35967f88 100644
--- a/chrome/browser/safe_browsing/advanced_protection_status_manager.h
+++ b/chrome/browser/safe_browsing/advanced_protection_status_manager.h
@@ -96,7 +96,7 @@
 
   void OnAdvancedProtectionDisabled();
 
-  void OnAccessTokenFetchComplete(std::string account_id,
+  void OnAccessTokenFetchComplete(CoreAccountId account_id,
                                   GoogleServiceAuthError error,
                                   signin::AccessTokenInfo token_info);
 
@@ -115,14 +115,15 @@
   bool IsUnconsentedPrimaryAccount(const CoreAccountInfo& account_info);
 
   // Decodes |id_token| to get advanced protection status.
-  void OnGetIDToken(const std::string& account_id, const std::string& id_token);
+  void OnGetIDToken(const CoreAccountId& account_id,
+                    const std::string& id_token);
 
   // Only called in tests.
   void SetMinimumRefreshDelay(const base::TimeDelta& delay);
 
   // Gets the account ID of the unconsented primary account of |profile_|.
   // Returns an empty string if user is not signed in.
-  std::string GetUnconsentedPrimaryAccountId() const;
+  CoreAccountId GetUnconsentedPrimaryAccountId() const;
 
   // Only called in tests to set a customized minimum delay.
   AdvancedProtectionStatusManager(PrefService* pref_service,
diff --git a/chrome/browser/safe_browsing/download_protection/binary_upload_service.cc b/chrome/browser/safe_browsing/download_protection/binary_upload_service.cc
index f4446cf..8545ac1 100644
--- a/chrome/browser/safe_browsing/download_protection/binary_upload_service.cc
+++ b/chrome/browser/safe_browsing/download_protection/binary_upload_service.cc
@@ -9,6 +9,7 @@
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/rand_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
index 997a08d75..94196d0 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -1609,10 +1609,10 @@
  public:
   explicit SecurityStyleTestObserver(content::WebContents* web_contents)
       : content::WebContentsObserver(web_contents),
-        latest_security_style_(blink::kWebSecurityStyleUnknown),
+        latest_security_style_(blink::SecurityStyle::kUnknown),
         latest_security_style_explanations_() {}
 
-  blink::WebSecurityStyle latest_security_style() const {
+  blink::SecurityStyle latest_security_style() const {
     return latest_security_style_;
   }
 
@@ -1628,7 +1628,7 @@
   }
 
  private:
-  blink::WebSecurityStyle latest_security_style_;
+  blink::SecurityStyle latest_security_style_;
   content::SecurityStyleExplanations latest_security_style_explanations_;
   DISALLOW_COPY_AND_ASSIGN(SecurityStyleTestObserver);
 };
@@ -1654,7 +1654,7 @@
   // The security indicator should be downgraded while the interstitial shows.
   SetupThreatIframeWarningAndNavigate();
   ExpectSecurityIndicatorDowngrade(error_tab, 0u);
-  EXPECT_EQ(blink::kWebSecurityStyleInsecure, observer.latest_security_style());
+  EXPECT_EQ(blink::SecurityStyle::kInsecure, observer.latest_security_style());
   // Security style summary for Developer Tools should contain a warning.
   EXPECT_EQ(l10n_util::GetStringUTF8(IDS_SAFEBROWSING_WARNING),
             observer.latest_security_style_explanations().summary);
diff --git a/chrome/browser/search/one_google_bar/one_google_bar_loader_impl.cc b/chrome/browser/search/one_google_bar/one_google_bar_loader_impl.cc
index 8331944..5e7c126 100644
--- a/chrome/browser/search/one_google_bar/one_google_bar_loader_impl.cc
+++ b/chrome/browser/search/one_google_bar/one_google_bar_loader_impl.cc
@@ -206,8 +206,8 @@
   std::string chrome_connected_header_value =
       chrome_connected_header_helper.BuildRequestHeader(
           /*is_header_request=*/true, api_url_,
-          // Account ID is only needed for (drive|docs).google.com.
-          /*account_id=*/std::string(), profile_mode);
+          // Gaia ID is only needed for (drive|docs).google.com.
+          /*gaia_id=*/std::string(), profile_mode);
   if (!chrome_connected_header_value.empty()) {
     request->headers.SetHeader(signin::kChromeConnectedHeader,
                                chrome_connected_header_value);
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.cc b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.cc
index 3a9fb771..5021b39 100644
--- a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.cc
+++ b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.cc
@@ -32,13 +32,15 @@
 }
 
 // static
-void ClickToCallUiController::ShowDialog(content::WebContents* web_contents,
-                                         const GURL& url,
-                                         bool hide_default_handler) {
+void ClickToCallUiController::ShowDialog(
+    content::WebContents* web_contents,
+    const base::Optional<url::Origin>& initiating_origin,
+    const GURL& url,
+    bool hide_default_handler) {
   auto* controller = GetOrCreateFromWebContents(web_contents);
   controller->phone_url_ = url;
   controller->hide_default_handler_ = hide_default_handler;
-  controller->UpdateAndShowDialog();
+  controller->UpdateAndShowDialog(initiating_origin);
 }
 
 ClickToCallUiController::ClickToCallUiController(
@@ -179,6 +181,8 @@
       IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_HELP_TEXT_NO_DEVICES;
   data.help_link_text_id =
       IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TROUBLESHOOT_LINK;
+  data.origin_text_id =
+      IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_INITIATING_ORIGIN;
 
   return data;
 }
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.h b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.h
index 646ae25..6af4a3e 100644
--- a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.h
+++ b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller.h
@@ -11,12 +11,14 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "chrome/browser/sharing/sharing_metrics.h"
 #include "chrome/browser/sharing/sharing_service.h"
 #include "chrome/browser/sharing/sharing_ui_controller.h"
 #include "chrome/browser/ui/page_action/page_action_icon_type.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "url/gurl.h"
+#include "url/origin.h"
 
 namespace content {
 class WebContents;
@@ -29,6 +31,7 @@
   static ClickToCallUiController* GetOrCreateFromWebContents(
       content::WebContents* web_contents);
   static void ShowDialog(content::WebContents* web_contents,
+                         const base::Optional<url::Origin>& initiating_origin,
                          const GURL& url,
                          bool hide_default_handler);
 
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc
index c6d0534..2d43dea 100644
--- a/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc
+++ b/chrome/browser/sharing/click_to_call/click_to_call_ui_controller_unittest.cc
@@ -94,7 +94,8 @@
               std::make_unique<SharingFCMHandler>(nullptr, nullptr, nullptr));
         }));
     ClickToCallUiController::ShowDialog(
-        web_contents_.get(), GURL(base::StrCat({"tel:", kPhoneNumber})), false);
+        web_contents_.get(), /*initiating_origin=*/base::nullopt,
+        GURL(base::StrCat({"tel:", kPhoneNumber})), false);
     controller_ = ClickToCallUiController::GetOrCreateFromWebContents(
         web_contents_.get());
   }
diff --git a/chrome/browser/sharing/sharing_browsertest.cc b/chrome/browser/sharing/sharing_browsertest.cc
index ab0fa6ce..664ce06 100644
--- a/chrome/browser/sharing/sharing_browsertest.cc
+++ b/chrome/browser/sharing/sharing_browsertest.cc
@@ -79,15 +79,19 @@
     std::unique_ptr<syncer::DeviceInfo> fake_device =
         std::make_unique<syncer::DeviceInfo>(
             device->guid(),
-            base::StrCat(
-                {"testing_device_", base::NumberToString(device_id++)}),
+            base::StrCat({"testing_device_", base::NumberToString(device_id)}),
             device->chrome_version(), device->sync_user_agent(),
             device->device_type(), device->signin_scoped_device_id(),
-            device->hardware_info(), device->last_updated_timestamp(),
+            base::SysInfo::HardwareInfo{
+                "Google",
+                base::StrCat({"model", base::NumberToString(device_id)}),
+                "serial_number"},
+            device->last_updated_timestamp(),
             device->send_tab_to_self_receiving_enabled(),
             device->sharing_info());
     fake_device_info_tracker_.Add(fake_device.get());
     device_infos_.push_back(std::move(fake_device));
+    device_id++;
   }
 }
 
diff --git a/chrome/browser/sharing/sharing_dialog_data.h b/chrome/browser/sharing/sharing_dialog_data.h
index c9f13c91..cbdfb7d 100644
--- a/chrome/browser/sharing/sharing_dialog_data.h
+++ b/chrome/browser/sharing/sharing_dialog_data.h
@@ -9,10 +9,12 @@
 #include <vector>
 
 #include "base/callback_forward.h"
+#include "base/optional.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/sharing/sharing_app.h"
 #include "chrome/browser/sharing/sharing_metrics.h"
 #include "components/sync_device_info/device_info.h"
+#include "url/origin.h"
 
 class SharingDialog;
 
@@ -36,6 +38,8 @@
   int help_link_text_id = 0;
   int header_image_light = 0;
   int header_image_dark = 0;
+  int origin_text_id = 0;
+  base::Optional<url::Origin> initiating_origin;
 
   base::OnceCallback<void(SharingDialogType)> help_callback;
   base::OnceCallback<void(const syncer::DeviceInfo&)> device_callback;
diff --git a/chrome/browser/sharing/sharing_service.cc b/chrome/browser/sharing/sharing_service.cc
index 0513526..67ea314 100644
--- a/chrome/browser/sharing/sharing_service.cc
+++ b/chrome/browser/sharing/sharing_service.cc
@@ -12,6 +12,7 @@
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/guid.h"
+#include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/time/time.h"
@@ -27,12 +28,108 @@
 #include "chrome/browser/sharing/sharing_metrics.h"
 #include "chrome/browser/sharing/sharing_sync_preference.h"
 #include "chrome/browser/sharing/vapid_key_manager.h"
+#include "chrome/grit/generated_resources.h"
 #include "components/gcm_driver/crypto/gcm_encryption_provider.h"
 #include "components/gcm_driver/gcm_driver.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync_device_info/device_info.h"
 #include "components/sync_device_info/local_device_info_provider.h"
 #include "content/public/browser/browser_task_traits.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+// Util function to return a string denoting the type of device.
+std::string GetDeviceType(sync_pb::SyncEnums::DeviceType type) {
+  int device_type_message_id = -1;
+
+  switch (type) {
+    case sync_pb::SyncEnums::TYPE_LINUX:
+    case sync_pb::SyncEnums::TYPE_WIN:
+    case sync_pb::SyncEnums::TYPE_CROS:
+    case sync_pb::SyncEnums::TYPE_MAC:
+      device_type_message_id = IDS_BROWSER_SHARING_DEVICE_TYPE_COMPUTER;
+      break;
+
+    case sync_pb::SyncEnums::TYPE_UNSET:
+    case sync_pb::SyncEnums::TYPE_OTHER:
+      device_type_message_id = IDS_BROWSER_SHARING_DEVICE_TYPE_DEVICE;
+      break;
+
+    case sync_pb::SyncEnums::TYPE_PHONE:
+      device_type_message_id = IDS_BROWSER_SHARING_DEVICE_TYPE_PHONE;
+      break;
+
+    case sync_pb::SyncEnums::TYPE_TABLET:
+      device_type_message_id = IDS_BROWSER_SHARING_DEVICE_TYPE_TABLET;
+      break;
+  }
+
+  return l10n_util::GetStringUTF8(device_type_message_id);
+}
+
+// Util function to get name for a single device. |is_full_name| determines
+// whether we should add the model name for the device.
+std::string GetDeviceName(const syncer::DeviceInfo* device, bool is_full_name) {
+  DCHECK(device);
+
+  base::SysInfo::HardwareInfo hardware_info = device->hardware_info();
+
+  // The model might be empty if other device is still on M78 or lower with sync
+  // turned on.
+  if (hardware_info.model.empty())
+    return device->client_name();
+
+  sync_pb::SyncEnums::DeviceType type = device->device_type();
+
+  // For chromeOS, return manufacturer + model.
+  if (type == sync_pb::SyncEnums::TYPE_CROS) {
+    return base::StrCat({device->hardware_info().manufacturer, " ",
+                         device->hardware_info().model});
+  }
+
+  if (hardware_info.manufacturer == "Apple Inc.") {
+    if (is_full_name)
+      return hardware_info.model;
+
+    // Returns a more readable hardware model. Internal names of Apple devices
+    // are formatted as MacbookPro2,3 or iPhone2,1 or Ipad4,1.
+    return hardware_info.model.substr(
+        0, hardware_info.model.find_first_of("0123456789,"));
+  }
+
+  std::string device_name =
+      base::StrCat({hardware_info.manufacturer, " ", GetDeviceType(type)});
+  if (is_full_name)
+    base::StrAppend(&device_name, {" ", hardware_info.model});
+
+  return device_name;
+}
+
+// Util function to rename devices for Sharing.
+std::vector<std::unique_ptr<syncer::DeviceInfo>> RenameDevices(
+    const std::vector<std::unique_ptr<syncer::DeviceInfo>>& devices) {
+  std::map<std::string, int> similar_devices_counter;
+  for (const auto& device : devices)
+    similar_devices_counter[GetDeviceName(device.get(),
+                                          /*is_full_name=*/false)]++;
+
+  std::vector<std::unique_ptr<syncer::DeviceInfo>> renamed_devices;
+  for (const auto& device : devices) {
+    bool is_full_name_required = similar_devices_counter[GetDeviceName(
+                                     device.get(), /*is_full_name=*/false)] > 1;
+    std::string device_name =
+        GetDeviceName(device.get(), is_full_name_required);
+
+    renamed_devices.push_back(std::make_unique<syncer::DeviceInfo>(
+        device->guid(), device_name, device->chrome_version(),
+        device->sync_user_agent(), device->device_type(),
+        device->signin_scoped_device_id(), device->hardware_info(),
+        device->last_updated_timestamp(),
+        device->send_tab_to_self_receiving_enabled(), device->sharing_info()));
+  }
+  return renamed_devices;
+}
+}  // namespace
 
 SharingService::SharingService(
     std::unique_ptr<SharingSyncPreference> sync_prefs,
@@ -128,6 +225,8 @@
   return device_info_tracker_->GetDeviceInfo(guid);
 }
 
+// TODO(crbug.com/1014107) - Simplify this function. The function does a number
+// of things and some calls are duplicated at the moment.
 std::vector<std::unique_ptr<syncer::DeviceInfo>>
 SharingService::GetDeviceCandidates(
     sync_pb::SharingSpecificFields::EnabledFeatures required_feature) const {
@@ -149,7 +248,11 @@
                      device2->last_updated_timestamp();
             });
 
-  std::unordered_set<std::string> device_names;
+  std::unordered_set<std::string> full_device_names;
+  // To prevent adding candidates with same name as local device.
+  full_device_names.insert(
+      GetDeviceName(local_device_info, /*is_full_name=*/true));
+
   for (auto& device : all_devices) {
     // If the current device is considered expired for our purposes, stop here
     // since the next devices in the vector are at least as expired than this
@@ -157,9 +260,6 @@
     if (device->last_updated_timestamp() < min_updated_time)
       break;
 
-    if (local_device_info->client_name() == device->client_name())
-      continue;
-
     base::Optional<syncer::DeviceInfo::SharingInfo> sharing_info =
         sync_prefs_->GetSharingInfo(device.get());
     if (!sharing_info ||
@@ -168,7 +268,8 @@
     }
 
     // Only insert the first occurrence of each device name.
-    auto inserted = device_names.insert(device->client_name());
+    auto inserted = full_device_names.insert(
+        GetDeviceName(device.get(), /*is_full_name=*/true));
     if (inserted.second)
       device_candidates.push_back(std::move(device));
   }
@@ -176,6 +277,8 @@
   // TODO(knollr): Remove devices from |sync_prefs_| that are in
   // |synced_devices| but not in |all_devices|?
 
+  device_candidates = RenameDevices(device_candidates);
+
   return device_candidates;
 }
 
diff --git a/chrome/browser/sharing/sharing_service_unittest.cc b/chrome/browser/sharing/sharing_service_unittest.cc
index 63e37500..17fd9c88 100644
--- a/chrome/browser/sharing/sharing_service_unittest.cc
+++ b/chrome/browser/sharing/sharing_service_unittest.cc
@@ -203,11 +203,14 @@
  protected:
   static std::unique_ptr<syncer::DeviceInfo> CreateFakeDeviceInfo(
       const std::string& id,
-      const std::string& name) {
+      const std::string& name,
+      sync_pb::SyncEnums_DeviceType device_type =
+          sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
+      base::SysInfo::HardwareInfo hardware_info =
+          base::SysInfo::HardwareInfo()) {
     return std::make_unique<syncer::DeviceInfo>(
-        id, name, "chrome_version", "user_agent",
-        sync_pb::SyncEnums_DeviceType_TYPE_LINUX, "device_id",
-        base::SysInfo::HardwareInfo(),
+        id, name, "chrome_version", "user_agent", device_type, "device_id",
+        hardware_info,
         /*last_updated_timestamp=*/base::Time::Now(),
         /*send_tab_to_self_receiving_enabled=*/false,
         syncer::DeviceInfo::SharingInfo(
@@ -342,9 +345,11 @@
 
 TEST_F(SharingServiceTest, GetDeviceCandidates_DuplicateDeviceNames) {
   // Add first device.
+  base::SysInfo::HardwareInfo info{"Google", "Pixel C", "serialno"};
+
   std::string id1 = base::GenerateGUID();
-  std::unique_ptr<syncer::DeviceInfo> device_info_1 =
-      CreateFakeDeviceInfo(id1, kDeviceName);
+  std::unique_ptr<syncer::DeviceInfo> device_info_1 = CreateFakeDeviceInfo(
+      id1, "Device1", sync_pb::SyncEnums_DeviceType_TYPE_TABLET, info);
   fake_device_info_sync_service.GetDeviceInfoTracker()->Add(
       device_info_1.get());
 
@@ -353,15 +358,19 @@
 
   // Add second device.
   std::string id2 = base::GenerateGUID();
-  std::unique_ptr<syncer::DeviceInfo> device_info_2 =
-      CreateFakeDeviceInfo(id2, kDeviceName);
+  std::unique_ptr<syncer::DeviceInfo> device_info_2 = CreateFakeDeviceInfo(
+      id2, "Device2", sync_pb::SyncEnums_DeviceType_TYPE_TABLET, info);
   fake_device_info_sync_service.GetDeviceInfoTracker()->Add(
       device_info_2.get());
 
-  // Add third device which is same as local device ("name").
+  // Add third device which is same as local device except guid.
   std::string id3 = base::GenerateGUID();
-  std::unique_ptr<syncer::DeviceInfo> device_info_3 =
-      CreateFakeDeviceInfo(id3, "name");
+  const syncer::DeviceInfo* local_device_info =
+      fake_device_info_sync_service.GetLocalDeviceInfoProvider()
+          ->GetLocalDeviceInfo();
+  std::unique_ptr<syncer::DeviceInfo> device_info_3 = CreateFakeDeviceInfo(
+      id3, local_device_info->client_name(), local_device_info->device_type(),
+      local_device_info->hardware_info());
   fake_device_info_sync_service.GetDeviceInfoTracker()->Add(
       device_info_3.get());
 
@@ -744,3 +753,133 @@
 
   ASSERT_TRUE(device_candidates_initialized_);
 }
+
+TEST_F(SharingServiceTest, DeviceCandidatesNames_Computers) {
+  std::unique_ptr<syncer::DeviceInfo> computer1 = CreateFakeDeviceInfo(
+      base::GenerateGUID(), "Fake device 1",
+      sync_pb::SyncEnums_DeviceType_TYPE_WIN, {"Dell", "PC3999", "sno one"});
+
+  fake_device_info_sync_service.GetDeviceInfoTracker()->Add(computer1.get());
+  std::vector<std::unique_ptr<syncer::DeviceInfo>> candidates =
+      GetSharingService()->GetDeviceCandidates(
+          sync_pb::SharingSpecificFields::CLICK_TO_CALL);
+
+  ASSERT_EQ(1u, candidates.size());
+  EXPECT_EQ("Dell Computer", candidates[0]->client_name());
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10));
+
+  std::unique_ptr<syncer::DeviceInfo> computer2 = CreateFakeDeviceInfo(
+      base::GenerateGUID(), "Fake device 2",
+      sync_pb::SyncEnums_DeviceType_TYPE_LINUX, {"Dell", "PC3998", "sno two"});
+
+  fake_device_info_sync_service.GetDeviceInfoTracker()->Add(computer2.get());
+  candidates = GetSharingService()->GetDeviceCandidates(
+      sync_pb::SharingSpecificFields::CLICK_TO_CALL);
+
+  ASSERT_EQ(2u, candidates.size());
+  EXPECT_EQ("Dell Computer PC3998", candidates[0]->client_name());
+  EXPECT_EQ("Dell Computer PC3999", candidates[1]->client_name());
+}
+
+TEST_F(SharingServiceTest, DeviceCandidatesNames_AppleDevices) {
+  std::unique_ptr<syncer::DeviceInfo> computer1 =
+      CreateFakeDeviceInfo(base::GenerateGUID(), "Fake device 1",
+                           sync_pb::SyncEnums_DeviceType_TYPE_TABLET,
+                           {"Apple Inc.", "iPad2,2", "sno one"});
+  fake_device_info_sync_service.GetDeviceInfoTracker()->Add(computer1.get());
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10));
+
+  std::unique_ptr<syncer::DeviceInfo> computer2 =
+      CreateFakeDeviceInfo(base::GenerateGUID(), "Fake device 2",
+                           sync_pb::SyncEnums_DeviceType_TYPE_PHONE,
+                           {"Apple Inc.", "iPhone1,1", "sno two"});
+  fake_device_info_sync_service.GetDeviceInfoTracker()->Add(computer2.get());
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10));
+
+  std::unique_ptr<syncer::DeviceInfo> computer3 =
+      CreateFakeDeviceInfo(base::GenerateGUID(), "Fake device 3",
+                           sync_pb::SyncEnums_DeviceType_TYPE_MAC,
+                           {"Apple Inc.", "MacbookPro1,1", "sno three"});
+  fake_device_info_sync_service.GetDeviceInfoTracker()->Add(computer3.get());
+
+  std::vector<std::unique_ptr<syncer::DeviceInfo>> candidates =
+      GetSharingService()->GetDeviceCandidates(
+          sync_pb::SharingSpecificFields::CLICK_TO_CALL);
+
+  ASSERT_EQ(3u, candidates.size());
+  EXPECT_EQ("MacbookPro", candidates[0]->client_name());
+  EXPECT_EQ("iPhone", candidates[1]->client_name());
+  EXPECT_EQ("iPad", candidates[2]->client_name());
+}
+
+TEST_F(SharingServiceTest, DeviceCandidatesNames_AndroidDevices) {
+  std::unique_ptr<syncer::DeviceInfo> computer1 =
+      CreateFakeDeviceInfo(base::GenerateGUID(), "Fake device 1",
+                           sync_pb::SyncEnums_DeviceType_TYPE_TABLET,
+                           {"Google", "Pixel Slate", "sno one"});
+  fake_device_info_sync_service.GetDeviceInfoTracker()->Add(computer1.get());
+
+  std::vector<std::unique_ptr<syncer::DeviceInfo>> candidates =
+      GetSharingService()->GetDeviceCandidates(
+          sync_pb::SharingSpecificFields::CLICK_TO_CALL);
+
+  ASSERT_EQ(1u, candidates.size());
+  EXPECT_EQ("Google Tablet", candidates[0]->client_name());
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10));
+
+  std::unique_ptr<syncer::DeviceInfo> computer2 =
+      CreateFakeDeviceInfo(base::GenerateGUID(), "Fake device 2",
+                           sync_pb::SyncEnums_DeviceType_TYPE_PHONE,
+                           {"Google", "Pixel 3", "sno two"});
+  fake_device_info_sync_service.GetDeviceInfoTracker()->Add(computer2.get());
+
+  candidates = GetSharingService()->GetDeviceCandidates(
+      sync_pb::SharingSpecificFields::CLICK_TO_CALL);
+
+  ASSERT_EQ(2u, candidates.size());
+  EXPECT_EQ("Google Phone", candidates[0]->client_name());
+  EXPECT_EQ("Google Tablet", candidates[1]->client_name());
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10));
+
+  std::unique_ptr<syncer::DeviceInfo> computer3 =
+      CreateFakeDeviceInfo(base::GenerateGUID(), "Fake device 3",
+                           sync_pb::SyncEnums_DeviceType_TYPE_PHONE,
+                           {"Google", "Pixel 2", "sno three"});
+  fake_device_info_sync_service.GetDeviceInfoTracker()->Add(computer3.get());
+
+  candidates = GetSharingService()->GetDeviceCandidates(
+      sync_pb::SharingSpecificFields::CLICK_TO_CALL);
+
+  ASSERT_EQ(3u, candidates.size());
+  EXPECT_EQ("Google Phone Pixel 2", candidates[0]->client_name());
+  EXPECT_EQ("Google Phone Pixel 3", candidates[1]->client_name());
+  EXPECT_EQ("Google Tablet", candidates[2]->client_name());
+}
+
+TEST_F(SharingServiceTest, DeviceCandidatesNames_Chromebooks) {
+  std::unique_ptr<syncer::DeviceInfo> computer1 =
+      CreateFakeDeviceInfo(base::GenerateGUID(), "Fake device 1",
+                           sync_pb::SyncEnums_DeviceType_TYPE_CROS,
+                           {"Dell", "Chromebook", "sno one"});
+  fake_device_info_sync_service.GetDeviceInfoTracker()->Add(computer1.get());
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10));
+
+  std::unique_ptr<syncer::DeviceInfo> computer2 = CreateFakeDeviceInfo(
+      base::GenerateGUID(), "Fake device 2",
+      sync_pb::SyncEnums_DeviceType_TYPE_CROS, {"HP", "Chromebook", "sno one"});
+  fake_device_info_sync_service.GetDeviceInfoTracker()->Add(computer2.get());
+
+  std::vector<std::unique_ptr<syncer::DeviceInfo>> candidates =
+      GetSharingService()->GetDeviceCandidates(
+          sync_pb::SharingSpecificFields::CLICK_TO_CALL);
+
+  ASSERT_EQ(2u, candidates.size());
+  EXPECT_EQ("HP Chromebook", candidates[0]->client_name());
+  EXPECT_EQ("Dell Chromebook", candidates[1]->client_name());
+}
diff --git a/chrome/browser/sharing/sharing_ui_controller.cc b/chrome/browser/sharing/sharing_ui_controller.cc
index 8a5ce86c..564756849 100644
--- a/chrome/browser/sharing/sharing_ui_controller.cc
+++ b/chrome/browser/sharing/sharing_ui_controller.cc
@@ -124,10 +124,12 @@
   CloseDialog();
 }
 
-void SharingUiController::UpdateAndShowDialog() {
+void SharingUiController::UpdateAndShowDialog(
+    const base::Optional<url::Origin>& initiating_origin) {
   ClearLastDialog();
   DoUpdateApps(base::BindOnce(&SharingUiController::OnAppsReceived,
-                              weak_ptr_factory_.GetWeakPtr(), last_dialog_id_));
+                              weak_ptr_factory_.GetWeakPtr(), last_dialog_id_,
+                              initiating_origin));
 }
 
 std::vector<std::unique_ptr<syncer::DeviceInfo>>
@@ -230,8 +232,10 @@
   UpdateIcon();
 }
 
-void SharingUiController::OnAppsReceived(int dialog_id,
-                                         std::vector<SharingApp> apps) {
+void SharingUiController::OnAppsReceived(
+    int dialog_id,
+    const base::Optional<url::Origin>& initiating_origin,
+    std::vector<SharingApp> apps) {
   if (dialog_id != last_dialog_id_)
     return;
 
@@ -241,6 +245,7 @@
       CreateDialogData(GetSharingDialogType(!devices.empty(), !apps.empty()));
   dialog_data.devices = std::move(devices);
   dialog_data.apps = std::move(apps);
+  dialog_data.initiating_origin = initiating_origin;
 
   ShowNewDialog(std::move(dialog_data));
 }
diff --git a/chrome/browser/sharing/sharing_ui_controller.h b/chrome/browser/sharing/sharing_ui_controller.h
index 9b73426..cbb148a 100644
--- a/chrome/browser/sharing/sharing_ui_controller.h
+++ b/chrome/browser/sharing/sharing_ui_controller.h
@@ -11,6 +11,7 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/sharing/proto/sharing_message.pb.h"
@@ -24,6 +25,7 @@
 #include "components/sync_device_info/device_info.h"
 #include "ui/views/controls/styled_label.h"
 #include "ui/views/controls/styled_label_listener.h"
+#include "url/origin.h"
 
 class SharingDialog;
 class SharingService;
@@ -74,7 +76,8 @@
   void ClearLastDialog();
 
   // Gets the current list of apps and devices and shows a new dialog.
-  void UpdateAndShowDialog();
+  void UpdateAndShowDialog(
+      const base::Optional<url::Origin>& initiating_origin);
 
   // Gets the current list of devices that support the required feature.
   std::vector<std::unique_ptr<syncer::DeviceInfo>> GetDevices();
@@ -120,7 +123,9 @@
   // |success| is false and updates the omnibox icon.
   void OnMessageSentToDevice(int dialog_id, SharingSendMessageResult result);
 
-  void OnAppsReceived(int dialog_id, std::vector<SharingApp> apps);
+  void OnAppsReceived(int dialog_id,
+                      const base::Optional<url::Origin>& initiating_origin,
+                      std::vector<SharingApp> apps);
 
   SharingDialog* dialog_ = nullptr;
   content::WebContents* web_contents_ = nullptr;
diff --git a/chrome/browser/signin/chrome_signin_helper.cc b/chrome/browser/signin/chrome_signin_helper.cc
index 1a35bf4..5f7981a8 100644
--- a/chrome/browser/signin/chrome_signin_helper.cc
+++ b/chrome/browser/signin/chrome_signin_helper.cc
@@ -255,7 +255,7 @@
                                 signin_metrics::PromoAction promo_action,
                                 signin_metrics::Reason reason,
                                 content::WebContents* web_contents,
-                                const std::string& account_id) {
+                                const CoreAccountId& account_id) {
   DCHECK(profile);
   Browser* browser = web_contents
                          ? chrome::FindBrowserWithWebContents(web_contents)
@@ -443,7 +443,7 @@
     bool is_off_the_record,
     int incognito_availibility,
     AccountConsistencyMethod account_consistency,
-    std::string primary_account_id,
+    std::string gaia_id,
 #if defined(OS_CHROMEOS)
     bool account_consistency_mirror_required,
 #endif
@@ -475,8 +475,8 @@
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
   // Dice header:
   bool dice_header_added = AppendOrRemoveDiceRequestHeader(
-      request, redirect_url, primary_account_id, is_sync_enabled,
-      account_consistency, cookie_settings, signin_scoped_device_id);
+      request, redirect_url, gaia_id, is_sync_enabled, account_consistency,
+      cookie_settings, signin_scoped_device_id);
 
   // Block the AccountReconcilor while the Dice requests are in flight. This
   // allows the DiceReponseHandler to process the response before the reconcilor
@@ -491,7 +491,7 @@
 #endif
 
   // Mirror header:
-  AppendOrRemoveMirrorRequestHeader(request, redirect_url, primary_account_id,
+  AppendOrRemoveMirrorRequestHeader(request, redirect_url, gaia_id,
                                     account_consistency, cookie_settings,
                                     profile_mode_mask);
 }
diff --git a/chrome/browser/signin/chrome_signin_helper.h b/chrome/browser/signin/chrome_signin_helper.h
index 988ec13..7b3f0e5e 100644
--- a/chrome/browser/signin/chrome_signin_helper.h
+++ b/chrome/browser/signin/chrome_signin_helper.h
@@ -89,7 +89,7 @@
     bool is_off_the_record,
     int incognito_availibility,
     AccountConsistencyMethod account_consistency,
-    std::string primary_account_id,
+    std::string gaia_id,
 #if defined(OS_CHROMEOS)
     bool account_consistency_mirror_required,
 #endif
diff --git a/chrome/browser/signin/dice_response_handler.cc b/chrome/browser/signin/dice_response_handler.cc
index ef5ac4e4..c503ba8 100644
--- a/chrome/browser/signin/dice_response_handler.cc
+++ b/chrome/browser/signin/dice_response_handler.cc
@@ -298,7 +298,7 @@
       return;  // There is already a request in flight with the same parameters.
     }
   }
-  std::string account_id =
+  CoreAccountId account_id =
       identity_manager_->PickAccountIdForAccount(gaia_id, email);
   delegate->EnableSync(account_id);
 }
@@ -307,12 +307,13 @@
     const std::vector<signin::DiceResponseParams::AccountInfo>& account_infos) {
   VLOG(1) << "Start processing Dice signout response";
 
-  std::string primary_account = identity_manager_->GetPrimaryAccountId();
+  CoreAccountId primary_account = identity_manager_->GetPrimaryAccountId();
   bool primary_account_signed_out = false;
   auto* accounts_mutator = identity_manager_->GetAccountsMutator();
   for (const auto& account_info : account_infos) {
-    std::string signed_out_account = identity_manager_->PickAccountIdForAccount(
-        account_info.gaia_id, account_info.email);
+    CoreAccountId signed_out_account =
+        identity_manager_->PickAccountIdForAccount(account_info.gaia_id,
+                                                   account_info.email);
     if (signed_out_account == primary_account) {
       primary_account_signed_out = true;
       RecordDiceResponseHeader(kSignoutPrimary);
@@ -335,7 +336,7 @@
 
     // If a token fetch is in flight for the same account, cancel it.
     for (auto it = token_fetchers_.begin(); it != token_fetchers_.end(); ++it) {
-      std::string token_fetcher_account_id =
+      CoreAccountId token_fetcher_account_id =
           identity_manager_->PickAccountIdForAccount(it->get()->gaia_id(),
                                                      it->get()->email());
       if (token_fetcher_account_id == signed_out_account) {
@@ -368,12 +369,12 @@
   VLOG(1) << "[Dice] OAuth success for email " << email;
   bool should_enable_sync = token_fetcher->should_enable_sync();
   auto* accounts_mutator = identity_manager_->GetAccountsMutator();
-  std::string account_id = accounts_mutator->AddOrUpdateAccount(
+  CoreAccountId account_id = accounts_mutator->AddOrUpdateAccount(
       gaia_id, email, refresh_token, is_under_advanced_protection,
       signin_metrics::SourceForRefreshTokenOperation::
           kDiceResponseHandler_Signin);
   about_signin_internals_->OnRefreshTokenReceived(
-      base::StringPrintf("Successful (%s)", account_id.c_str()));
+      base::StringPrintf("Successful (%s)", account_id.id.c_str()));
   if (should_enable_sync)
     token_fetcher->delegate()->EnableSync(account_id);
 
@@ -385,10 +386,10 @@
     const GoogleServiceAuthError& error) {
   const std::string& email = token_fetcher->email();
   const std::string& gaia_id = token_fetcher->gaia_id();
-  std::string account_id =
+  CoreAccountId account_id =
       identity_manager_->PickAccountIdForAccount(gaia_id, email);
   about_signin_internals_->OnRefreshTokenReceived(
-      base::StringPrintf("Failure (%s)", account_id.c_str()));
+      base::StringPrintf("Failure (%s)", account_id.id.c_str()));
   token_fetcher->delegate()->HandleTokenExchangeFailure(email, error);
 
   DeleteTokenFetcher(token_fetcher);
diff --git a/chrome/browser/signin/dice_response_handler.h b/chrome/browser/signin/dice_response_handler.h
index ab6eac1..b80bf4f 100644
--- a/chrome/browser/signin/dice_response_handler.h
+++ b/chrome/browser/signin/dice_response_handler.h
@@ -39,7 +39,7 @@
   // Asks the delegate to enable sync for the |account_id|.
   // Called after the account was seeded in the account tracker service and
   // after the refresh token was fetched and updated in the token service.
-  virtual void EnableSync(const std::string& account_id) = 0;
+  virtual void EnableSync(const CoreAccountId& account_id) = 0;
 
   // Handles a failure in the token exchange (i.e. shows the error to the user).
   virtual void HandleTokenExchangeFailure(
diff --git a/chrome/browser/signin/dice_response_handler_unittest.cc b/chrome/browser/signin/dice_response_handler_unittest.cc
index 93758714..322e831 100644
--- a/chrome/browser/signin/dice_response_handler_unittest.cc
+++ b/chrome/browser/signin/dice_response_handler_unittest.cc
@@ -203,7 +203,7 @@
   ~TestProcessDiceHeaderDelegate() override = default;
 
   // Called after the refresh token was fetched and added in the token service.
-  void EnableSync(const std::string& account_id) override {
+  void EnableSync(const CoreAccountId& account_id) override {
     owner_->EnableSync(account_id);
   }
 
diff --git a/chrome/browser/signin/header_modification_delegate_impl.cc b/chrome/browser/signin/header_modification_delegate_impl.cc
index 230cf71..b1010d43 100644
--- a/chrome/browser/signin/header_modification_delegate_impl.cc
+++ b/chrome/browser/signin/header_modification_delegate_impl.cc
@@ -63,7 +63,9 @@
       request_adapter, redirect_url, profile_->IsOffTheRecord(),
       prefs->GetInteger(prefs::kIncognitoModeAvailability),
       AccountConsistencyModeManager::GetMethodForProfile(profile_),
-      IdentityManagerFactory::GetForProfile(profile_)->GetPrimaryAccountId(),
+      IdentityManagerFactory::GetForProfile(profile_)
+          ->GetPrimaryAccountInfo()
+          .gaia,
 #if defined(OS_CHROMEOS)
       prefs->GetBoolean(prefs::kAccountConsistencyMirrorRequired),
 #endif
diff --git a/chrome/browser/signin/process_dice_header_delegate_impl.cc b/chrome/browser/signin/process_dice_header_delegate_impl.cc
index 01203537..086ffee0 100644
--- a/chrome/browser/signin/process_dice_header_delegate_impl.cc
+++ b/chrome/browser/signin/process_dice_header_delegate_impl.cc
@@ -63,7 +63,8 @@
   return true;
 }
 
-void ProcessDiceHeaderDelegateImpl::EnableSync(const std::string& account_id) {
+void ProcessDiceHeaderDelegateImpl::EnableSync(
+    const CoreAccountId& account_id) {
   if (!ShouldEnableSync()) {
     // No special treatment is needed if the user is not enabling sync.
     return;
diff --git a/chrome/browser/signin/process_dice_header_delegate_impl.h b/chrome/browser/signin/process_dice_header_delegate_impl.h
index 2ecdc49..53b7a50 100644
--- a/chrome/browser/signin/process_dice_header_delegate_impl.h
+++ b/chrome/browser/signin/process_dice_header_delegate_impl.h
@@ -29,7 +29,7 @@
   // Callback starting Sync.
   using EnableSyncCallback =
       base::OnceCallback<void(content::WebContents*,
-                              const std::string& /* account_id */)>;
+                              const CoreAccountId& /* account_id */)>;
 
   // Callback showing a signin error UI.
   using ShowSigninErrorCallback =
@@ -50,7 +50,7 @@
   ~ProcessDiceHeaderDelegateImpl() override;
 
   // ProcessDiceHeaderDelegate:
-  void EnableSync(const std::string& account_id) override;
+  void EnableSync(const CoreAccountId& account_id) override;
   void HandleTokenExchangeFailure(const std::string& email,
                                   const GoogleServiceAuthError& error) override;
 
diff --git a/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc b/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc
index 5eaf96f4..75aff8a 100644
--- a/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc
+++ b/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc
@@ -54,7 +54,7 @@
 
   // Callback for the ProcessDiceHeaderDelegateImpl.
   void StartSyncCallback(content::WebContents* contents,
-                         const std::string& account_id) {
+                         const CoreAccountId& account_id) {
     EXPECT_EQ(web_contents(), contents);
     EXPECT_EQ(account_id_, account_id);
     enable_sync_called_ = true;
@@ -74,7 +74,7 @@
 
   bool enable_sync_called_;
   bool show_error_called_;
-  std::string account_id_;
+  CoreAccountId account_id_;
   std::string email_;
   GoogleServiceAuthError auth_error_;
 };
diff --git a/chrome/browser/signin/signin_error_notifier_ash.cc b/chrome/browser/signin/signin_error_notifier_ash.cc
index 94333a9..f0475c1 100644
--- a/chrome/browser/signin/signin_error_notifier_ash.cc
+++ b/chrome/browser/signin/signin_error_notifier_ash.cc
@@ -15,6 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/account_manager/account_manager_util.h"
 #include "chrome/browser/chromeos/login/user_flow.h"
 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
diff --git a/chrome/browser/signin/signin_ui_util.cc b/chrome/browser/signin/signin_ui_util.cc
index 9090a743..f65ddf9 100644
--- a/chrome/browser/signin/signin_ui_util.cc
+++ b/chrome/browser/signin/signin_ui_util.cc
@@ -110,7 +110,7 @@
     signin_metrics::AccessPoint signin_access_point,
     signin_metrics::PromoAction signin_promo_action,
     signin_metrics::Reason signin_reason,
-    const std::string& account_id,
+    const CoreAccountId& account_id,
     DiceTurnSyncOnHelper::SigninAbortedMode signin_aborted_mode) {
   // DiceTurnSyncOnHelper is suicidal (it will delete itself once it finishes
   // enabling sync).
@@ -186,7 +186,7 @@
              signin_metrics::AccessPoint signin_access_point,
              signin_metrics::PromoAction signin_promo_action,
              signin_metrics::Reason signin_reason,
-             const std::string& account_id,
+             const CoreAccountId& account_id,
              DiceTurnSyncOnHelper::SigninAbortedMode signin_aborted_mode)>
         create_dice_turn_sync_on_helper_callback) {
   DCHECK(browser);
@@ -244,7 +244,7 @@
       identity_manager->GetExtendedAccountInfoForAccountsWithRefreshToken();
 
   // Compute the default account.
-  std::string default_account_id;
+  CoreAccountId default_account_id;
   if (identity_manager->HasPrimaryAccount()) {
     default_account_id = identity_manager->GetPrimaryAccountId();
   } else {
diff --git a/chrome/browser/signin/signin_ui_util.h b/chrome/browser/signin/signin_ui_util.h
index 807c5508..0248a4c6 100644
--- a/chrome/browser/signin/signin_ui_util.h
+++ b/chrome/browser/signin/signin_ui_util.h
@@ -89,7 +89,7 @@
              signin_metrics::AccessPoint signin_access_point,
              signin_metrics::PromoAction signin_promo_action,
              signin_metrics::Reason signin_reason,
-             const std::string& account_id,
+             const CoreAccountId& account_id,
              DiceTurnSyncOnHelper::SigninAbortedMode signin_aborted_mode)>
         create_dice_turn_sync_on_helper_callback);
 }  // namespace internal
diff --git a/chrome/browser/signin/signin_ui_util_unittest.cc b/chrome/browser/signin/signin_ui_util_unittest.cc
index f2ea790..a40daf93 100644
--- a/chrome/browser/signin/signin_ui_util_unittest.cc
+++ b/chrome/browser/signin/signin_ui_util_unittest.cc
@@ -104,7 +104,7 @@
     signin_metrics::PromoAction signin_promo_action =
         signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO;
     signin_metrics::Reason signin_reason = signin_metrics::Reason::REASON_MAX;
-    std::string account_id;
+    CoreAccountId account_id;
     DiceTurnSyncOnHelper::SigninAbortedMode signin_aborted_mode =
         DiceTurnSyncOnHelper::SigninAbortedMode::REMOVE_ACCOUNT;
   };
@@ -115,7 +115,7 @@
       signin_metrics::AccessPoint signin_access_point,
       signin_metrics::PromoAction signin_promo_action,
       signin_metrics::Reason signin_reason,
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       DiceTurnSyncOnHelper::SigninAbortedMode signin_aborted_mode) {
     create_dice_turn_sync_on_helper_called_ = true;
     create_dice_turn_sync_on_helper_params_.profile = profile;
diff --git a/chrome/browser/ssl/cert_report_helper.cc b/chrome/browser/ssl/cert_report_helper.cc
index ce88dce..0fe235c 100644
--- a/chrome/browser/ssl/cert_report_helper.cc
+++ b/chrome/browser/ssl/cert_report_helper.cc
@@ -15,6 +15,7 @@
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ssl/ssl_cert_reporter.h"
 #include "chrome/common/channel_info.h"
diff --git a/chrome/browser/ssl/security_state_tab_helper.h b/chrome/browser/ssl/security_state_tab_helper.h
index 33d84e5..2a23c52a 100644
--- a/chrome/browser/ssl/security_state_tab_helper.h
+++ b/chrome/browser/ssl/security_state_tab_helper.h
@@ -11,7 +11,7 @@
 #include "components/security_state/core/security_state.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
-#include "third_party/blink/public/platform/web_security_style.h"
+#include "third_party/blink/public/common/security/security_style.h"
 
 namespace content {
 class NavigationHandle;
diff --git a/chrome/browser/ssl/security_state_tab_helper_browsertest.cc b/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
index 074eb371..aee0592 100644
--- a/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
+++ b/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
@@ -215,7 +215,7 @@
  public:
   explicit SecurityStyleTestObserver(content::WebContents* web_contents)
       : content::WebContentsObserver(web_contents),
-        latest_security_style_(blink::kWebSecurityStyleUnknown) {}
+        latest_security_style_(blink::SecurityStyle::kUnknown) {}
   ~SecurityStyleTestObserver() override {}
 
   void DidChangeVisibleSecurityState() override {
@@ -228,7 +228,7 @@
 
   void WaitForDidChangeVisibleSecurityState() { run_loop_.Run(); }
 
-  blink::WebSecurityStyle latest_security_style() const {
+  blink::SecurityStyle latest_security_style() const {
     return latest_security_style_;
   }
 
@@ -237,12 +237,12 @@
   }
 
   void ClearLatestSecurityStyleAndExplanations() {
-    latest_security_style_ = blink::kWebSecurityStyleUnknown;
+    latest_security_style_ = blink::SecurityStyle::kUnknown;
     latest_explanations_ = content::SecurityStyleExplanations();
   }
 
  private:
-  blink::WebSecurityStyle latest_security_style_;
+  blink::SecurityStyle latest_security_style_;
   content::SecurityStyleExplanations latest_explanations_;
   base::RunLoop run_loop_;
   DISALLOW_COPY_AND_ASSIGN(SecurityStyleTestObserver);
@@ -254,7 +254,7 @@
                               int error,
                               Browser* browser,
                               net::X509Certificate* expected_cert) {
-  EXPECT_EQ(blink::kWebSecurityStyleInsecure, observer.latest_security_style());
+  EXPECT_EQ(blink::SecurityStyle::kInsecure, observer.latest_security_style());
 
   const content::SecurityStyleExplanations& expired_explanation =
       observer.latest_explanations();
@@ -1039,7 +1039,7 @@
   // Ensure that WebContentsObservers don't show an incorrect Form Not Secure
   // explanation. Regression test for https://crbug.com/691412.
   EXPECT_EQ(0u, observer.latest_explanations().neutral_explanations.size());
-  EXPECT_EQ(blink::kWebSecurityStyleNeutral, observer.latest_security_style());
+  EXPECT_EQ(blink::SecurityStyle::kNeutral, observer.latest_security_style());
 
   content::NavigationEntry* entry = contents->GetController().GetVisibleEntry();
   ASSERT_TRUE(entry);
@@ -1161,7 +1161,7 @@
   // Ensure that WebContentsObservers don't show an incorrect Form Not Secure
   // explanation. Regression test for https://crbug.com/691412.
   EXPECT_EQ(0u, observer.latest_explanations().neutral_explanations.size());
-  EXPECT_EQ(blink::kWebSecurityStyleNeutral, observer.latest_security_style());
+  EXPECT_EQ(blink::SecurityStyle::kNeutral, observer.latest_security_style());
 
   content::NavigationEntry* entry = contents->GetController().GetVisibleEntry();
   ASSERT_TRUE(entry);
@@ -1553,7 +1553,7 @@
   // Visit an HTTP url.
   GURL http_url(embedded_test_server()->GetURL("/title1.html"));
   ui_test_utils::NavigateToURL(browser(), http_url);
-  EXPECT_EQ(blink::kWebSecurityStyleNeutral, observer.latest_security_style());
+  EXPECT_EQ(blink::SecurityStyle::kNeutral, observer.latest_security_style());
   EXPECT_EQ(0u, observer.latest_explanations().neutral_explanations.size());
   EXPECT_EQ(0u, observer.latest_explanations().insecure_explanations.size());
   EXPECT_EQ(0u, observer.latest_explanations().secure_explanations.size());
@@ -1571,7 +1571,7 @@
 
   GURL mixed_content_url(https_server_.GetURL(replacement_path));
   ui_test_utils::NavigateToURL(browser(), mixed_content_url);
-  EXPECT_EQ(blink::kWebSecurityStyleNeutral, observer.latest_security_style());
+  EXPECT_EQ(blink::SecurityStyle::kNeutral, observer.latest_security_style());
 
   const content::SecurityStyleExplanations& mixed_content_explanation =
       observer.latest_explanations();
@@ -1609,7 +1609,7 @@
   // back to the interstitial.
   GURL valid_https_url(https_server_.GetURL("/title1.html"));
   ui_test_utils::NavigateToURL(browser(), valid_https_url);
-  EXPECT_EQ(blink::kWebSecurityStyleSecure, observer.latest_security_style());
+  EXPECT_EQ(blink::SecurityStyle::kSecure, observer.latest_security_style());
   EXPECT_EQ(0u, observer.latest_explanations().neutral_explanations.size());
   EXPECT_EQ(0u, observer.latest_explanations().insecure_explanations.size());
   ASSERT_EQ(3u, observer.latest_explanations().secure_explanations.size());
@@ -1695,7 +1695,7 @@
   ui_test_utils::NavigateToURL(browser(), http_url);
 
   EXPECT_EQ(security_state::DANGEROUS, helper->GetSecurityLevel());
-  EXPECT_EQ(blink::kWebSecurityStyleInsecure, observer.latest_security_style());
+  EXPECT_EQ(blink::SecurityStyle::kInsecure, observer.latest_security_style());
   const content::SecurityStyleExplanations& http_explanation =
       observer.latest_explanations();
   EXPECT_EQ(l10n_util::GetStringUTF8(IDS_HTTP_NONSECURE_SUMMARY),
@@ -1730,7 +1730,7 @@
   // Visit a valid HTTPS url.
   GURL valid_https_url(https_server_.GetURL("/title1.html"));
   ui_test_utils::NavigateToURL(browser(), valid_https_url);
-  EXPECT_EQ(blink::kWebSecurityStyleSecure, observer.latest_security_style());
+  EXPECT_EQ(blink::SecurityStyle::kSecure, observer.latest_security_style());
   EXPECT_EQ(0u, observer.latest_explanations().neutral_explanations.size());
   EXPECT_EQ(0u, observer.latest_explanations().insecure_explanations.size());
   ASSERT_EQ(3u, observer.latest_explanations().secure_explanations.size());
@@ -1777,7 +1777,7 @@
   chrome::GoBack(browser(), WindowOpenDisposition::CURRENT_TAB);
   back_nav_load_observer.Wait();
 
-  EXPECT_EQ(blink::kWebSecurityStyleSecure, observer.latest_security_style());
+  EXPECT_EQ(blink::SecurityStyle::kSecure, observer.latest_security_style());
   EXPECT_EQ(0u, observer.latest_explanations().neutral_explanations.size());
   EXPECT_EQ(0u, observer.latest_explanations().insecure_explanations.size());
   ASSERT_EQ(3u, observer.latest_explanations().secure_explanations.size());
@@ -1868,8 +1868,8 @@
       browser(), GURL(std::string("https://") + kMockNonsecureHostname));
 
   // The security style of the page doesn't get downgraded for obsolete
-  // TLS settings, so it should remain at WebSecurityStyleSecure.
-  EXPECT_EQ(blink::kWebSecurityStyleSecure, observer.latest_security_style());
+  // TLS settings, so it should remain at SecurityStyleSecure.
+  EXPECT_EQ(blink::SecurityStyle::kSecure, observer.latest_security_style());
 
   for (const auto& explanation :
        observer.latest_explanations().secure_explanations) {
diff --git a/chrome/browser/ssl/ssl_error_handler.cc b/chrome/browser/ssl/ssl_error_handler.cc
index 53b13d37..58a3172 100644
--- a/chrome/browser/ssl/ssl_error_handler.cc
+++ b/chrome/browser/ssl/ssl_error_handler.cc
@@ -22,6 +22,7 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ssl/bad_clock_blocking_page.h"
 #include "chrome/browser/ssl/captive_portal_blocking_page.h"
diff --git a/chrome/browser/subresource_filter/android_test_ruleset_publisher.cc b/chrome/browser/subresource_filter/android_test_ruleset_publisher.cc
index 26f8787..9ede63fa 100644
--- a/chrome/browser/subresource_filter/android_test_ruleset_publisher.cc
+++ b/chrome/browser/subresource_filter/android_test_ruleset_publisher.cc
@@ -8,6 +8,7 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
+#include "base/bind.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/subresource_filter/jni_headers/TestRulesetPublisher_jni.h"
diff --git a/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc b/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc
index d8f1eb1..30e9088 100644
--- a/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_custom_passphrase_sync_test.cc
@@ -13,6 +13,8 @@
 #include "components/sync/engine/sync_engine_switches.h"
 #include "components/sync/nigori/cryptographer.h"
 #include "content/public/test/test_launcher.h"
+#include "crypto/sha2.h"
+#include "testing/gmock/include/gmock/gmock.h"
 
 namespace {
 
@@ -36,6 +38,7 @@
 using syncer::PassphraseType;
 using syncer::ProtoPassphraseInt32ToEnum;
 using syncer::SyncService;
+using testing::SizeIs;
 
 class DatatypeCommitCountingFakeServerObserver : public FakeServer::Observer {
  public:
@@ -262,6 +265,41 @@
   EXPECT_TRUE(WaitForClientBookmarkWithTitle("PBKDF2-encrypted bookmark"));
 }
 
+IN_PROC_BROWSER_TEST_P(SingleClientCustomPassphraseSyncTestWithUssTests,
+                       ShouldExposeExperimentalAuthenticationId) {
+  const std::vector<std::string>& keystore_keys =
+      GetFakeServer()->GetKeystoreKeys();
+  ASSERT_THAT(keystore_keys, SizeIs(1));
+
+  KeyParams key_params = {KeyDerivationParams::CreateForPbkdf2(), "hunter2"};
+  SetNigoriInFakeServer(GetFakeServer(),
+                        CreateCustomPassphraseNigori(key_params));
+  SetupSyncNoWaitingForCompletion();
+  ASSERT_TRUE(WaitForPassphraseRequiredState(/*desired_state=*/true));
+
+  // WARNING: Do *NOT* change these values since the authentication ID should be
+  // stable across different browser versions.
+
+  // Default birthday determined by LoopbackServer.
+  const std::string kDefaultBirthday = "0";
+  const std::string kSeparator("|");
+  std::string base64_encoded_keystore_key;
+  base::Base64Encode(keystore_keys.back(), &base64_encoded_keystore_key);
+  const std::string authentication_id_before_hashing =
+      std::string("gaia_id_for_user_gmail.com") + kSeparator +
+      kDefaultBirthday + kSeparator + base64_encoded_keystore_key;
+
+  EXPECT_EQ(GetSyncService()->GetExperimentalAuthenticationId(),
+            crypto::SHA256HashString(authentication_id_before_hashing));
+
+  // Entering the passphrase should not influence the authentication ID.
+  ASSERT_TRUE(
+      GetSyncService()->GetUserSettings()->SetDecryptionPassphrase("hunter2"));
+  ASSERT_TRUE(WaitForPassphraseRequiredState(/*desired_state=*/false));
+  EXPECT_EQ(GetSyncService()->GetExperimentalAuthenticationId(),
+            crypto::SHA256HashString(authentication_id_before_hashing));
+}
+
 INSTANTIATE_TEST_SUITE_P(USS,
                          SingleClientCustomPassphraseSyncTestWithUssTests,
                          testing::Values(false, true));
diff --git a/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc b/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
index 5f96aa4..d9aec80 100644
--- a/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
@@ -17,12 +17,14 @@
 #include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/nigori/cryptographer_impl.h"
 #include "components/sync/nigori/nigori.h"
+#include "crypto/sha2.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace {
 
 using encryption_helper::GetServerNigori;
 using encryption_helper::SetNigoriInFakeServer;
+using testing::SizeIs;
 
 struct KeyParams {
   syncer::KeyDerivationParams derivation_params;
@@ -152,7 +154,7 @@
                        ShouldDecryptWithKeystoreNigori) {
   const std::vector<std::string>& keystore_keys =
       GetFakeServer()->GetKeystoreKeys();
-  ASSERT_EQ(keystore_keys.size(), size_t{1});
+  ASSERT_THAT(keystore_keys, SizeIs(1));
   const KeyParams kKeystoreKeyParams = KeystoreKeyParams(keystore_keys.back());
   SetNigoriInFakeServer(GetFakeServer(),
                         BuildKeystoreNigoriSpecifics(
@@ -177,7 +179,7 @@
                        ShouldDecryptWithBackwardCompatibleKeystoreNigori) {
   const std::vector<std::string>& keystore_keys =
       GetFakeServer()->GetKeystoreKeys();
-  ASSERT_EQ(keystore_keys.size(), size_t{1});
+  ASSERT_THAT(keystore_keys, SizeIs(1));
   const KeyParams kKeystoreKeyParams = KeystoreKeyParams(keystore_keys.back());
   const KeyParams kDefaultKeyParams = {
       syncer::KeyDerivationParams::CreateForPbkdf2(), "password"};
@@ -196,6 +198,36 @@
   EXPECT_TRUE(WaitForPasswordForms({password_form}));
 }
 
+IN_PROC_BROWSER_TEST_P(SingleClientNigoriSyncTestWithUssTests,
+                       ShouldExposeExperimentalAuthenticationId) {
+  const std::vector<std::string>& keystore_keys =
+      GetFakeServer()->GetKeystoreKeys();
+  ASSERT_THAT(keystore_keys, SizeIs(1));
+  const KeyParams kKeystoreKeyParams = KeystoreKeyParams(keystore_keys.back());
+  SetNigoriInFakeServer(GetFakeServer(),
+                        BuildKeystoreNigoriSpecifics(
+                            /*keybag_keys_params=*/{kKeystoreKeyParams},
+                            /*keystore_decryptor_params=*/kKeystoreKeyParams,
+                            /*keystore_key_params=*/kKeystoreKeyParams));
+
+  ASSERT_TRUE(SetupSync());
+
+  // WARNING: Do *NOT* change these values since the authentication ID should be
+  // stable across different browser versions.
+
+  // Default birthday determined by LoopbackServer.
+  const std::string kDefaultBirthday = "0";
+  const std::string kSeparator("|");
+  std::string base64_encoded_keystore_key;
+  base::Base64Encode(keystore_keys.back(), &base64_encoded_keystore_key);
+  const std::string authentication_id_before_hashing =
+      std::string("gaia_id_for_user_gmail.com") + kSeparator +
+      kDefaultBirthday + kSeparator + base64_encoded_keystore_key;
+
+  EXPECT_EQ(GetSyncService(/*index=*/0)->GetExperimentalAuthenticationId(),
+            crypto::SHA256HashString(authentication_id_before_hashing));
+}
+
 INSTANTIATE_TEST_SUITE_P(USS,
                          SingleClientNigoriSyncTestWithUssTests,
                          ::testing::Values(false, true));
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 0eaed71..4e7ffc6 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -19,6 +19,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
diff --git a/chrome/browser/touch_to_fill/android/internal/BUILD.gn b/chrome/browser/touch_to_fill/android/internal/BUILD.gn
index 4b27588d..a274f3a0 100644
--- a/chrome/browser/touch_to_fill/android/internal/BUILD.gn
+++ b/chrome/browser/touch_to_fill/android/internal/BUILD.gn
@@ -13,17 +13,18 @@
     "//chrome/android:chrome_java",
     "//chrome/browser/touch_to_fill/android:public_java",
     "//chrome/browser/util/android:java",
+    "//third_party/android_deps:com_android_support_recyclerview_v7_java",
     "//ui/android:ui_java",
   ]
 
   java_files = [
-    "java/src/org/chromium/chrome/browser/touch_to_fill/CredentialProperties.java",
     "java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillBridge.java",
     "java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillCoordinator.java",
     "java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java",
     "java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillProperties.java",
     "java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillView.java",
     "java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java",
+    "java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewHolder.java",
   ]
 
   annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
diff --git a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml
index 1180edf6..20a668d 100644
--- a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml
+++ b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_credential_item.xml
@@ -8,6 +8,7 @@
     android:descendantFocusability="blocksDescendants"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:layout_marginBottom="8dp"
     android:minHeight="72dp"
     android:gravity="center_vertical"
     android:orientation="horizontal"
diff --git a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_sheet.xml b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_sheet.xml
index b4c4175..3223dc1 100644
--- a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_sheet.xml
+++ b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_sheet.xml
@@ -44,14 +44,14 @@
         android:layout_gravity="center_horizontal"
         android:textAppearance="@style/TextAppearance.BlackHint1" />
 
-    <ListView
-        android:id="@+id/credential_list"
+    <android.support.v7.widget.RecyclerView
+        android:id="@+id/sheet_item_list"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layout_marginTop="16dp"
+        android:minHeight="200dp"
+        android:layout_marginTop="24dp"
         android:clipToPadding="false"
         android:paddingBottom="16dp"
         android:divider="@null"
-        android:dividerHeight="8dp"
         tools:listitem="@layout/touch_to_fill_credential_item"/>
 </LinearLayout>
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/CredentialProperties.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/CredentialProperties.java
deleted file mode 100644
index 3fdcb98..0000000
--- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/CredentialProperties.java
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.touch_to_fill;
-
-import android.graphics.Bitmap;
-
-import org.chromium.chrome.browser.touch_to_fill.data.Credential;
-import org.chromium.ui.modelutil.PropertyModel;
-
-/**
- * Properties for a credential entry in TouchToFill sheet.
- */
-class CredentialProperties {
-    static final int DEFAULT_ITEM_TYPE = 0; // Credential list has only one entry type.
-
-    static final PropertyModel.WritableObjectPropertyKey<Bitmap> FAVICON =
-            new PropertyModel.WritableObjectPropertyKey<>("favicon");
-    static final PropertyModel.WritableObjectPropertyKey<Credential> CREDENTIAL =
-            new PropertyModel.WritableObjectPropertyKey<>("credential");
-}
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java
index af73205..358809d 100644
--- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java
+++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java
@@ -4,19 +4,20 @@
 
 package org.chromium.chrome.browser.touch_to_fill;
 
-import static org.chromium.chrome.browser.touch_to_fill.CredentialProperties.CREDENTIAL;
-import static org.chromium.chrome.browser.touch_to_fill.CredentialProperties.DEFAULT_ITEM_TYPE;
-import static org.chromium.chrome.browser.touch_to_fill.CredentialProperties.FAVICON;
-import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CREDENTIAL_LIST;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.CREDENTIAL;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.FAVICON;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.ON_CLICK_LISTENER;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.FORMATTED_URL;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.ORIGIN_SECURE;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.SHEET_ITEMS;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.VISIBLE;
 
 import androidx.annotation.Px;
 
+import org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties;
 import org.chromium.chrome.browser.touch_to_fill.data.Credential;
-import org.chromium.ui.modelutil.MVCListAdapter;
-import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
+import org.chromium.ui.modelutil.ListModel;
+import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
 import org.chromium.ui.modelutil.PropertyModel;
 
 import java.util.List;
@@ -45,25 +46,23 @@
         mModel.set(ORIGIN_SECURE, isOriginSecure);
         mModel.set(VISIBLE, true);
 
-        ModelList credentialList = mModel.get(CREDENTIAL_LIST);
-        credentialList.clear();
+        ListModel<ListItem> sheetItems = mModel.get(SHEET_ITEMS);
+        sheetItems.clear();
         for (Credential credential : credentials) {
-            PropertyModel propertyModel = new PropertyModel.Builder(FAVICON, CREDENTIAL)
-                                                  .with(FAVICON, null)
-                                                  .with(CREDENTIAL, credential)
-                                                  .build();
-            credentialList.add(new MVCListAdapter.ListItem(DEFAULT_ITEM_TYPE, propertyModel));
+            PropertyModel propertyModel =
+                    new PropertyModel.Builder(CredentialProperties.ALL_KEYS)
+                            .with(CREDENTIAL, credential)
+                            .with(ON_CLICK_LISTENER, this::onSelectedCredential)
+                            .build();
+            sheetItems.add(new ListItem(TouchToFillProperties.ItemType.CREDENTIAL, propertyModel));
             mDelegate.fetchFavicon(credential.getOriginUrl(), mDesiredFaviconSize,
                     (bitmap) -> propertyModel.set(FAVICON, bitmap));
         }
     }
 
-    @Override
-    public void onSelectItemAt(int position) {
-        ModelList credentialList = mModel.get(CREDENTIAL_LIST);
-        assert position >= 0 && position < credentialList.size();
+    private void onSelectedCredential(Credential credential) {
         mModel.set(VISIBLE, false);
-        mDelegate.onCredentialSelected(credentialList.get(position).model.get(CREDENTIAL));
+        mDelegate.onCredentialSelected(credential);
     }
 
     @Override
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillProperties.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillProperties.java
index a52ca84..9269385 100644
--- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillProperties.java
+++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillProperties.java
@@ -4,9 +4,20 @@
 
 package org.chromium.chrome.browser.touch_to_fill;
 
-import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
+import android.graphics.Bitmap;
+
+import androidx.annotation.IntDef;
+
+import org.chromium.base.Callback;
+import org.chromium.chrome.browser.touch_to_fill.data.Credential;
+import org.chromium.ui.modelutil.ListModel;
+import org.chromium.ui.modelutil.MVCListAdapter;
+import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Properties defined here reflect the visible state of the TouchToFill-components.
  */
@@ -17,36 +28,71 @@
             new PropertyModel.WritableObjectPropertyKey<>("formatted_url");
     static final PropertyModel.WritableBooleanPropertyKey ORIGIN_SECURE =
             new PropertyModel.WritableBooleanPropertyKey("origin_secure");
-    static final PropertyModel.ReadableObjectPropertyKey<ModelList> CREDENTIAL_LIST =
-            new PropertyModel.ReadableObjectPropertyKey<>("credential_list");
+    static final PropertyModel
+            .ReadableObjectPropertyKey<ListModel<MVCListAdapter.ListItem>> SHEET_ITEMS =
+            new PropertyModel.ReadableObjectPropertyKey<>("sheet_items");
     static final PropertyModel.ReadableObjectPropertyKey<ViewEventListener> VIEW_EVENT_LISTENER =
             new PropertyModel.ReadableObjectPropertyKey<>("view_event_listener");
 
     static PropertyModel createDefaultModel(ViewEventListener listener) {
         return new PropertyModel
-                .Builder(
-                        VISIBLE, FORMATTED_URL, ORIGIN_SECURE, CREDENTIAL_LIST, VIEW_EVENT_LISTENER)
+                .Builder(VISIBLE, FORMATTED_URL, ORIGIN_SECURE, SHEET_ITEMS, VIEW_EVENT_LISTENER)
                 .with(VISIBLE, false)
                 .with(ORIGIN_SECURE, false)
-                .with(CREDENTIAL_LIST, new ModelList())
+                .with(SHEET_ITEMS, new ListModel<>())
                 .with(VIEW_EVENT_LISTENER, listener)
                 .build();
     }
 
     /**
+     * Properties for a credential entry in TouchToFill sheet.
+     */
+    static class CredentialProperties {
+        static final PropertyModel.WritableObjectPropertyKey<Bitmap> FAVICON =
+                new PropertyModel.WritableObjectPropertyKey<>("favicon");
+        static final PropertyModel.ReadableObjectPropertyKey<Credential> CREDENTIAL =
+                new PropertyModel.ReadableObjectPropertyKey<>("credential");
+        static final PropertyModel
+                .ReadableObjectPropertyKey<Callback<Credential>> ON_CLICK_LISTENER =
+                new PropertyModel.ReadableObjectPropertyKey<>("on_click_listener");
+
+        static final PropertyKey[] ALL_KEYS = {FAVICON, CREDENTIAL, ON_CLICK_LISTENER};
+
+        private CredentialProperties() {}
+    }
+
+    /**
      * This interface is used by the view to communicate events back to the mediator. It abstracts
      * from the view by stripping information like parents, id or context.
      */
     interface ViewEventListener {
-        /**
-         * Called if the user selected an item from the list.
-         * @param position The position that the user selected.
-         */
-        void onSelectItemAt(int position);
 
         /** Called if the user dismissed the view. */
         void onDismissed();
     }
 
+    @IntDef({ItemType.HEADER, ItemType.CREDENTIAL})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface ItemType {
+        /**
+         * The header at the top of the touch to fill sheet.
+         */
+        int HEADER = 1;
+
+        /**
+         * A section containing a user's name and password.
+         */
+        int CREDENTIAL = 2;
+    }
+
+    /**
+     * Returns the sheet item type for a given item.
+     * @param item An {@link MVCListAdapter.ListItem}.
+     * @return The {@link ItemType} of the given list item.
+     */
+    static @ItemType int getItemType(MVCListAdapter.ListItem item) {
+        return item.type;
+    }
+
     private TouchToFillProperties() {}
 }
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillView.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillView.java
index 3258329..156e62e 100644
--- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillView.java
+++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillView.java
@@ -6,12 +6,11 @@
 
 import android.content.Context;
 import android.support.annotation.Nullable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.AdapterView;
 import android.widget.LinearLayout;
-import android.widget.ListAdapter;
-import android.widget.ListView;
 import android.widget.TextView;
 
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
@@ -27,7 +26,7 @@
 class TouchToFillView implements BottomSheet.BottomSheetContent {
     private final Context mContext;
     private final BottomSheetController mBottomSheetController;
-    private final ListView mCredentialListView;
+    private final RecyclerView mSheetItemListView;
     private final LinearLayout mContentView;
     private TouchToFillProperties.ViewEventListener mEventListener;
 
@@ -51,8 +50,10 @@
         mBottomSheetController = bottomSheetController;
         mContentView = (LinearLayout) LayoutInflater.from(mContext).inflate(
                 R.layout.touch_to_fill_sheet, null);
-        mCredentialListView = mContentView.findViewById(R.id.credential_list);
-        mCredentialListView.setOnItemClickListener(this::onItemSelected);
+        mSheetItemListView = mContentView.findViewById(R.id.sheet_item_list);
+        mSheetItemListView.setLayoutManager(new LinearLayoutManager(
+                mSheetItemListView.getContext(), LinearLayoutManager.VERTICAL, false));
+        mSheetItemListView.setItemAnimator(null);
     }
 
     /**
@@ -96,20 +97,14 @@
         sheetSubtitleText.setText(subtitleText);
     }
 
-    void setCredentialListAdapter(ListAdapter adapter) {
-        mCredentialListView.setAdapter(adapter);
+    void setSheetItemListAdapter(RecyclerView.Adapter adapter) {
+        mSheetItemListView.setAdapter(adapter);
     }
 
     Context getContext() {
         return mContext;
     }
 
-    private void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
-        assert adapterView == mCredentialListView : "Use this click handler only for credentials!";
-        assert mEventListener != null;
-        mEventListener.onSelectItemAt(i);
-    }
-
     @Override
     public void destroy() {
         mBottomSheetController.getBottomSheet().removeObserver(mBottomSheetObserver);
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java
index 4e84d94..8a3b8d5 100644
--- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java
+++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java
@@ -4,25 +4,29 @@
 
 package org.chromium.chrome.browser.touch_to_fill;
 
-import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CREDENTIAL_LIST;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.CREDENTIAL;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.FAVICON;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.ON_CLICK_LISTENER;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.FORMATTED_URL;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.ORIGIN_SECURE;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.SHEET_ITEMS;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.VIEW_EVENT_LISTENER;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.VISIBLE;
 import static org.chromium.chrome.browser.util.UrlUtilities.stripScheme;
 
-import android.content.Context;
 import android.text.method.PasswordTransformationMethod;
-import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.ItemType;
 import org.chromium.chrome.browser.touch_to_fill.data.Credential;
-import org.chromium.ui.modelutil.ModelListAdapter;
+import org.chromium.ui.modelutil.MVCListAdapter;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.modelutil.RecyclerViewAdapter;
+import org.chromium.ui.modelutil.SimpleRecyclerViewMcp;
 
 /**
  * Provides functions that map {@link TouchToFillProperties} changes in a {@link PropertyModel} to
@@ -30,49 +34,6 @@
  */
 class TouchToFillViewBinder {
     /**
-     * Factory used to create a new View inside the ListView inside the TouchToFillView.
-     * @param parent The parent {@link ViewGroup} of the new item.
-     */
-    static View createCredentialView(Context context) {
-        return LayoutInflater.from(context).inflate(
-                R.layout.touch_to_fill_credential_item, null, false);
-    }
-
-    /**
-     * Called whenever a credential is bound to this view holder. Please note that this method
-     * might be called on the same list entry repeatedly, so make sure to always set a default for
-     * unused fields.
-     * @param model The model containing the data for the view
-     * @param view The view to be bound
-     * @param propertyKey The key of the property to be bound
-     */
-    static void bindCredentialView(PropertyModel model, View view, PropertyKey propertyKey) {
-        if (propertyKey == CredentialProperties.FAVICON) {
-            ImageView imageView = view.findViewById(R.id.favicon);
-            imageView.setImageBitmap(model.get(CredentialProperties.FAVICON));
-        } else if (propertyKey == CredentialProperties.CREDENTIAL) {
-            Credential credential = model.get(CredentialProperties.CREDENTIAL);
-
-            TextView pslOriginText = view.findViewById(R.id.credential_origin);
-            String formattedOrigin = stripScheme(credential.getOriginUrl());
-            formattedOrigin =
-                    formattedOrigin.replaceFirst("/$", ""); // Strip possibly trailing slash.
-            pslOriginText.setText(formattedOrigin);
-            pslOriginText.setVisibility(
-                    credential.isPublicSuffixMatch() ? View.VISIBLE : View.GONE);
-
-            TextView usernameText = view.findViewById(R.id.username);
-            usernameText.setText(credential.getFormattedUsername());
-
-            TextView passwordText = view.findViewById(R.id.password);
-            passwordText.setText(credential.getPassword());
-            passwordText.setTransformationMethod(new PasswordTransformationMethod());
-        } else {
-            assert false : "Every possible property update needs to be handled!";
-        }
-    }
-
-    /**
      * Called whenever a property in the given model changes. It updates the given view accordingly.
      * @param model The observed {@link PropertyModel}. Its data need to be reflected in the view.
      * @param view The {@link TouchToFillView} to update.
@@ -90,14 +51,81 @@
             } else {
                 view.setNonSecureSubtitle(model.get(FORMATTED_URL));
             }
-        } else if (propertyKey == CREDENTIAL_LIST) {
-            ModelListAdapter adapter = new ModelListAdapter(model.get(CREDENTIAL_LIST));
-            adapter.registerType(CredentialProperties.DEFAULT_ITEM_TYPE,
-                    () -> TouchToFillViewBinder.createCredentialView(view.getContext()),
-                    TouchToFillViewBinder::bindCredentialView);
-            view.setCredentialListAdapter(adapter);
+        } else if (propertyKey == SHEET_ITEMS) {
+            view.setSheetItemListAdapter(
+                    new RecyclerViewAdapter<>(new SimpleRecyclerViewMcp<>(model.get(SHEET_ITEMS),
+                                                      TouchToFillProperties::getItemType,
+                                                      TouchToFillViewBinder::connectPropertyModel),
+                            TouchToFillViewBinder::createViewHolder));
         } else {
-            assert false : "Every possible property update needs to be handled!";
+            assert false : "Unhandled update to property:" + propertyKey;
+        }
+    }
+
+    /**
+     * Factory used to create a new View inside the ListView inside the TouchToFillView.
+     * @param parent The parent {@link ViewGroup} of the new item.
+     * @param itemType The type of View to create.
+     */
+    private static TouchToFillViewHolder createViewHolder(
+            ViewGroup parent, @ItemType int itemType) {
+        switch (itemType) {
+            case ItemType.HEADER:
+                return null;
+            case ItemType.CREDENTIAL:
+                return new TouchToFillViewHolder(parent, R.layout.touch_to_fill_credential_item,
+                        TouchToFillViewBinder::bindCredentialView);
+        }
+        assert false : "Cannot create view for ItemType: " + itemType;
+        return null;
+    }
+
+    /**
+     * This method creates a model change processor for each recycler view item when it is created.
+     * @param holder A {@link TouchToFillViewHolder} holding the view and view binder for the MCP.
+     * @param item A {@link MVCListAdapter.ListItem} holding the {@link PropertyModel} for the MCP.
+     */
+    private static void connectPropertyModel(
+            TouchToFillViewHolder holder, MVCListAdapter.ListItem item) {
+        holder.setupModelChangeProcessor(item.model);
+    }
+
+    /**
+     * Called whenever a credential is bound to this view holder. Please note that this method
+     * might be called on the same list entry repeatedly, so make sure to always set a default
+     * for unused fields.
+     * @param model The model containing the data for the view
+     * @param view The view to be bound
+     * @param propertyKey The key of the property to be bound
+     */
+    private static void bindCredentialView(
+            PropertyModel model, ViewGroup view, PropertyKey propertyKey) {
+        if (propertyKey == FAVICON) {
+            ImageView imageView = view.findViewById(R.id.favicon);
+            imageView.setImageBitmap(model.get(FAVICON));
+        } else if (propertyKey == ON_CLICK_LISTENER) {
+            view.setOnClickListener(clickedView -> {
+                model.get(ON_CLICK_LISTENER).onResult(model.get(CREDENTIAL));
+            });
+        } else if (propertyKey == CREDENTIAL) {
+            Credential credential = model.get(CREDENTIAL);
+
+            TextView pslOriginText = view.findViewById(R.id.credential_origin);
+            String formattedOrigin = stripScheme(credential.getOriginUrl());
+            formattedOrigin =
+                    formattedOrigin.replaceFirst("/$", ""); // Strip possibly trailing slash.
+            pslOriginText.setText(formattedOrigin);
+            pslOriginText.setVisibility(
+                    credential.isPublicSuffixMatch() ? View.VISIBLE : View.GONE);
+
+            TextView usernameText = view.findViewById(R.id.username);
+            usernameText.setText(credential.getFormattedUsername());
+
+            TextView passwordText = view.findViewById(R.id.password);
+            passwordText.setText(credential.getPassword());
+            passwordText.setTransformationMethod(new PasswordTransformationMethod());
+        } else {
+            assert false : "Unhandled update to property:" + propertyKey;
         }
     }
 
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewHolder.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewHolder.java
new file mode 100644
index 0000000..b1136ff
--- /dev/null
+++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewHolder.java
@@ -0,0 +1,35 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.touch_to_fill;
+
+import android.support.annotation.LayoutRes;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
+import org.chromium.ui.modelutil.PropertyModelChangeProcessor.ViewBinder;
+
+class TouchToFillViewHolder extends RecyclerView.ViewHolder {
+    final ViewBinder<PropertyModel, ViewGroup, PropertyKey> mViewBinder;
+
+    TouchToFillViewHolder(ViewGroup parent, @LayoutRes int layout,
+            ViewBinder<PropertyModel, ViewGroup, PropertyKey> viewBinder) {
+        super(LayoutInflater.from(parent.getContext()).inflate(layout, parent, false));
+        mViewBinder = viewBinder;
+    }
+
+    /**
+     * Called whenever an item is bound to this view holder. Please note that this method
+     * might be called on the same list entry repeatedly, so make sure to always set a default
+     * for unused fields.
+     * @param model The {@link PropertyModel} whose data needs to be displayed.
+     */
+    void setupModelChangeProcessor(PropertyModel model) {
+        PropertyModelChangeProcessor.create(model, (ViewGroup) itemView, mViewBinder, true);
+    }
+}
\ No newline at end of file
diff --git a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java
index b15ad440..43dea74c 100644
--- a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java
+++ b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java
@@ -5,6 +5,8 @@
 package org.chromium.chrome.browser.touch_to_fill;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
@@ -14,7 +16,7 @@
 
 import android.support.test.espresso.Espresso;
 import android.support.test.filters.MediumTest;
-import android.widget.ListView;
+import android.support.v7.widget.RecyclerView;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -36,6 +38,7 @@
 import org.chromium.content_public.browser.test.util.TouchCommon;
 
 import java.util.Arrays;
+import java.util.Collections;
 
 /**
  * Integration tests for the Touch To Fill component check that the calls to the Touch To Fill API
@@ -77,14 +80,15 @@
     @DisabledTest(message = "crbug.com/1012221")
     public void testClickingSuggestionsTriggersCallback() {
         runOnUiThreadBlocking(() -> {
-            mTouchToFill.showCredentials(EXAMPLE_URL, true, Arrays.asList(ANA, BOB));
+            mTouchToFill.showCredentials(EXAMPLE_URL, true, Collections.singletonList(ANA));
         });
         pollUiThread(() -> getBottomSheetState() == SheetState.FULL);
 
-        pollUiThread(() -> getCredentials().getChildAt(1) != null);
-        TouchCommon.singleClickView(getCredentials().getChildAt(1));
+        pollUiThread(() -> getCredentials().getChildAt(0) != null);
+        TouchCommon.singleClickView(getCredentials().getChildAt(0));
 
-        waitForEvent(mMockBridge).onCredentialSelected(BOB);
+        waitForEvent(mMockBridge).onCredentialSelected(ANA);
+        verify(mMockBridge).fetchFavicon(eq(ANA.getOriginUrl()), anyInt(), any());
         verify(mMockBridge, never()).onDismissed();
     }
 
@@ -102,8 +106,8 @@
         verify(mMockBridge, never()).onCredentialSelected(any());
     }
 
-    private ListView getCredentials() {
-        return mActivityTestRule.getActivity().findViewById(R.id.credential_list);
+    private RecyclerView getCredentials() {
+        return mActivityTestRule.getActivity().findViewById(R.id.sheet_item_list);
     }
 
     public static <T> T waitForEvent(T mock) {
diff --git a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java
index 9bdd577..e4409aef 100644
--- a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java
+++ b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java
@@ -8,22 +8,24 @@
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 
-import static org.chromium.chrome.browser.touch_to_fill.CredentialProperties.CREDENTIAL;
-import static org.chromium.chrome.browser.touch_to_fill.CredentialProperties.DEFAULT_ITEM_TYPE;
-import static org.chromium.chrome.browser.touch_to_fill.CredentialProperties.FAVICON;
-import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CREDENTIAL_LIST;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.CREDENTIAL;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.ON_CLICK_LISTENER;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.FORMATTED_URL;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.ORIGIN_SECURE;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.SHEET_ITEMS;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.VISIBLE;
 import static org.chromium.content_public.browser.test.util.CriteriaHelper.pollUiThread;
 
+import static java.util.Arrays.asList;
+
 import android.support.test.filters.MediumTest;
+import android.support.v7.widget.RecyclerView;
 import android.text.method.PasswordTransformationMethod;
 import android.view.View;
-import android.widget.ListView;
 import android.widget.TextView;
 
 import org.junit.Before;
@@ -33,6 +35,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import org.chromium.base.Callback;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.ScalableTimeout;
 import org.chromium.chrome.browser.ChromeActivity;
@@ -47,14 +50,24 @@
 import org.chromium.ui.modelutil.MVCListAdapter;
 import org.chromium.ui.modelutil.PropertyModel;
 
+import java.util.Collections;
+
 /**
  * View tests for the Touch To Fill component ensure that model changes are reflected in the sheet.
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class TouchToFillViewTest {
+    private static final Credential ANA = new Credential("Ana", "S3cr3t", "Ana", "", false);
+    private static final Credential NO_ONE =
+            new Credential("", "***", "No Username", "http://m.example.xyz/", true);
+    private static final Credential BOB =
+            new Credential("Bob", "***", "Bob", "http://mobile.example.xyz", true);
+
     @Mock
     private TouchToFillProperties.ViewEventListener mMockListener;
+    @Mock
+    private Callback<Credential> mCredentialCallback;
 
     private PropertyModel mModel;
     private TouchToFillView mTouchToFillView;
@@ -62,12 +75,9 @@
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
 
-    public TouchToFillViewTest() {
-        MockitoAnnotations.initMocks(this);
-    }
-
     @Before
     public void setUp() throws InterruptedException {
+        MockitoAnnotations.initMocks(this);
         mActivityTestRule.startMainActivityOnBlankPage();
         mModel = TouchToFillProperties.createDefaultModel(mMockListener);
         TestThreadUtils.runOnUiThreadBlocking(() -> {
@@ -118,31 +128,28 @@
     public void testCredentialsChangedByModel() {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             mTouchToFillView.setVisible(true);
-            MVCListAdapter.ModelList credentialList = mModel.get(CREDENTIAL_LIST);
-            credentialList.add(buildCredentialItem("Ana", "S3cr3t", "Ana", "", false));
-            credentialList.add(
-                    buildCredentialItem("", "***", "No Username", "http://m.example.xyz/", true));
-            credentialList.add(
-                    buildCredentialItem("Bob", "***", "Bob", "http://mobile.example.xyz", true));
+            mModel.get(SHEET_ITEMS)
+                    .addAll(asList(buildCredentialItem(ANA), buildCredentialItem(NO_ONE),
+                            buildCredentialItem(BOB)));
         });
 
         pollUiThread(() -> getBottomSheetState() == SheetState.FULL);
         assertThat(getCredentials().getChildCount(), is(3));
         assertThat(getCredentialOriginAt(0).getVisibility(), is(View.GONE));
-        assertThat(getCredentialNameAt(0).getText(), is("Ana"));
-        assertThat(getCredentialPasswordAt(0).getText(), is("S3cr3t"));
+        assertThat(getCredentialNameAt(0).getText(), is(ANA.getFormattedUsername()));
+        assertThat(getCredentialPasswordAt(0).getText(), is(ANA.getPassword()));
         assertThat(getCredentialPasswordAt(0).getTransformationMethod(),
                 instanceOf(PasswordTransformationMethod.class));
         assertThat(getCredentialOriginAt(1).getVisibility(), is(View.VISIBLE));
         assertThat(getCredentialOriginAt(1).getText(), is("m.example.xyz"));
-        assertThat(getCredentialNameAt(1).getText(), is("No Username"));
-        assertThat(getCredentialPasswordAt(1).getText(), is("***"));
+        assertThat(getCredentialNameAt(1).getText(), is(NO_ONE.getFormattedUsername()));
+        assertThat(getCredentialPasswordAt(1).getText(), is(NO_ONE.getPassword()));
         assertThat(getCredentialPasswordAt(1).getTransformationMethod(),
                 instanceOf(PasswordTransformationMethod.class));
         assertThat(getCredentialOriginAt(2).getVisibility(), is(View.VISIBLE));
         assertThat(getCredentialOriginAt(2).getText(), is("mobile.example.xyz"));
-        assertThat(getCredentialNameAt(2).getText(), is("Bob"));
-        assertThat(getCredentialPasswordAt(2).getText(), is("***"));
+        assertThat(getCredentialNameAt(2).getText(), is(BOB.getFormattedUsername()));
+        assertThat(getCredentialPasswordAt(2).getText(), is(BOB.getPassword()));
         assertThat(getCredentialPasswordAt(2).getTransformationMethod(),
                 instanceOf(PasswordTransformationMethod.class));
     }
@@ -151,19 +158,16 @@
     @MediumTest
     public void testCredentialsAreClickable() {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mModel.get(CREDENTIAL_LIST)
-                    .add(buildCredentialItem("Carl", "G3h3!m", "Carl", "", false));
-            mModel.get(CREDENTIAL_LIST)
-                    .add(buildCredentialItem("Bob", "***", "Bob", "m.example.xyz", true));
+            mModel.get(SHEET_ITEMS).addAll(Collections.singletonList(buildCredentialItem(ANA)));
             mModel.set(VISIBLE, true);
         });
         pollUiThread(() -> getBottomSheetState() == SheetState.FULL);
 
-        assertNotNull(getCredentials().getChildAt(1));
+        assertNotNull(getCredentials().getChildAt(0));
 
-        TouchCommon.singleClickView(getCredentials().getChildAt(1));
+        TouchCommon.singleClickView(getCredentials().getChildAt(0));
 
-        waitForEvent().onSelectItemAt(1);
+        waitForEvent(mCredentialCallback).onResult(eq(ANA));
     }
 
     @Test
@@ -189,8 +193,8 @@
         return getActivity().getBottomSheet().getSheetState();
     }
 
-    private ListView getCredentials() {
-        return mTouchToFillView.getContentView().findViewById(R.id.credential_list);
+    private RecyclerView getCredentials() {
+        return mTouchToFillView.getContentView().findViewById(R.id.sheet_item_list);
     }
 
     private TextView getCredentialNameAt(int index) {
@@ -205,20 +209,16 @@
         return getCredentials().getChildAt(index).findViewById(R.id.credential_origin);
     }
 
-    TouchToFillProperties.ViewEventListener waitForEvent() {
-        return verify(mMockListener,
+    public static <T> T waitForEvent(T mock) {
+        return verify(mock,
                 timeout(ScalableTimeout.scaleTimeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL)));
     }
 
-    private static MVCListAdapter.ListItem buildCredentialItem(String username, String password,
-            String formattedUsername, String originUrl, boolean isPublicSuffixMatch) {
-        PropertyModel propertyModel =
-                new PropertyModel.Builder(FAVICON, CREDENTIAL)
-                        .with(FAVICON, null)
-                        .with(CREDENTIAL,
-                                new Credential(username, password, formattedUsername, originUrl,
-                                        isPublicSuffixMatch))
-                        .build();
-        return new MVCListAdapter.ListItem(DEFAULT_ITEM_TYPE, propertyModel);
+    private MVCListAdapter.ListItem buildCredentialItem(Credential credential) {
+        return new MVCListAdapter.ListItem(TouchToFillProperties.ItemType.CREDENTIAL,
+                new PropertyModel.Builder(TouchToFillProperties.CredentialProperties.ALL_KEYS)
+                        .with(CREDENTIAL, credential)
+                        .with(ON_CLICK_LISTENER, mCredentialCallback)
+                        .build());
     }
 }
diff --git a/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java b/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java
index 7b7c382e..7268c9f 100644
--- a/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java
+++ b/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java
@@ -13,10 +13,12 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import static org.chromium.chrome.browser.touch_to_fill.CredentialProperties.DEFAULT_ITEM_TYPE;
-import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CREDENTIAL_LIST;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.CREDENTIAL;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.FAVICON;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.ON_CLICK_LISTENER;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.FORMATTED_URL;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.ORIGIN_SECURE;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.SHEET_ITEMS;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.VIEW_EVENT_LISTENER;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.VISIBLE;
 
@@ -34,7 +36,9 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.ItemType;
 import org.chromium.chrome.browser.touch_to_fill.data.Credential;
+import org.chromium.ui.modelutil.ListModel;
 import org.chromium.ui.modelutil.MVCListAdapter;
 import org.chromium.ui.modelutil.PropertyModel;
 
@@ -77,7 +81,7 @@
 
     @Test
     public void testCreatesValidDefaultModel() {
-        assertNotNull(mModel.get(CREDENTIAL_LIST));
+        assertNotNull(mModel.get(SHEET_ITEMS));
         assertNotNull(mModel.get(VIEW_EVENT_LISTENER));
         assertThat(mModel.get(VISIBLE), is(false));
         assertThat(mModel.get(FORMATTED_URL), is(nullValue()));
@@ -94,18 +98,19 @@
     @Test
     public void testShowCredentialsSetsCredentialListAndRequestsFavicons() {
         mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL, BOB));
-        MVCListAdapter.ModelList credentialList = mModel.get(CREDENTIAL_LIST);
+        ListModel<MVCListAdapter.ListItem> credentialList = mModel.get(SHEET_ITEMS);
         assertThat(credentialList.size(), is(3));
         // TODO(https://crbug.com/1013209): Simplify this after adding equals to ModelList.
-        assertThat(credentialList.get(0).type, is(DEFAULT_ITEM_TYPE));
-        assertThat(credentialList.get(0).model.get(CredentialProperties.CREDENTIAL), is(ANA));
-        assertThat(credentialList.get(0).model.get(CredentialProperties.FAVICON), is(nullValue()));
-        assertThat(credentialList.get(1).type, is(DEFAULT_ITEM_TYPE));
-        assertThat(credentialList.get(1).model.get(CredentialProperties.CREDENTIAL), is(CARL));
-        assertThat(credentialList.get(1).model.get(CredentialProperties.FAVICON), is(nullValue()));
-        assertThat(credentialList.get(2).type, is(DEFAULT_ITEM_TYPE));
-        assertThat(credentialList.get(2).model.get(CredentialProperties.CREDENTIAL), is(BOB));
-        assertThat(credentialList.get(2).model.get(CredentialProperties.FAVICON), is(nullValue()));
+        assertThat(credentialList.size(), is(3));
+        assertThat(credentialList.get(0).type, is(ItemType.CREDENTIAL));
+        assertThat(credentialList.get(0).model.get(CREDENTIAL), is(ANA));
+        assertThat(credentialList.get(0).model.get(FAVICON), is(nullValue()));
+        assertThat(credentialList.get(1).type, is(TouchToFillProperties.ItemType.CREDENTIAL));
+        assertThat(credentialList.get(1).model.get(CREDENTIAL), is(CARL));
+        assertThat(credentialList.get(1).model.get(FAVICON), is(nullValue()));
+        assertThat(credentialList.get(2).type, is(TouchToFillProperties.ItemType.CREDENTIAL));
+        assertThat(credentialList.get(2).model.get(CREDENTIAL), is(BOB));
+        assertThat(credentialList.get(2).model.get(FAVICON), is(nullValue()));
 
         // ANA and CARL both have TEST_URL as their origin URL
         verify(mMockDelegate, times(2)).fetchFavicon(eq(TEST_URL), eq(DESIRED_FAVICON_SIZE), any());
@@ -115,12 +120,12 @@
     @Test
     public void testFetchFaviconUpdatesModel() {
         mMediator.showCredentials(TEST_URL, true, Collections.singletonList(CARL));
-        MVCListAdapter.ModelList credentialList = mModel.get(CREDENTIAL_LIST);
+        ListModel<MVCListAdapter.ListItem> credentialList = mModel.get(SHEET_ITEMS);
         assertThat(credentialList.size(), is(1));
         // TODO(https://crbug.com/1013209): Simplify this after adding equals to ModelList.
-        assertThat(credentialList.get(0).type, is(DEFAULT_ITEM_TYPE));
-        assertThat(credentialList.get(0).model.get(CredentialProperties.CREDENTIAL), is(CARL));
-        assertThat(credentialList.get(0).model.get(CredentialProperties.FAVICON), is(nullValue()));
+        assertThat(credentialList.get(0).type, is(TouchToFillProperties.ItemType.CREDENTIAL));
+        assertThat(credentialList.get(0).model.get(CREDENTIAL), is(CARL));
+        assertThat(credentialList.get(0).model.get(FAVICON), is(nullValue()));
 
         // ANA and CARL both have TEST_URL as their origin URL
         verify(mMockDelegate)
@@ -130,27 +135,27 @@
         Bitmap bitmap = Bitmap.createBitmap(
                 DESIRED_FAVICON_SIZE, DESIRED_FAVICON_SIZE, Bitmap.Config.ARGB_8888);
         callback.onResult(bitmap);
-        assertThat(credentialList.get(0).model.get(CredentialProperties.FAVICON), is(bitmap));
+        assertThat(credentialList.get(0).model.get(FAVICON), is(bitmap));
     }
 
     @Test
     public void testClearsCredentialListWhenShowingAgain() {
         mMediator.showCredentials(TEST_URL, true, Collections.singletonList(ANA));
-        MVCListAdapter.ModelList credentialList = mModel.get(CREDENTIAL_LIST);
+        ListModel<MVCListAdapter.ListItem> credentialList = mModel.get(SHEET_ITEMS);
         // TODO(https://crbug.com/1013209): Simplify this after adding equals to ModelList.
         assertThat(credentialList.size(), is(1));
-        assertThat(credentialList.get(0).type, is(DEFAULT_ITEM_TYPE));
-        assertThat(credentialList.get(0).model.get(CredentialProperties.CREDENTIAL), is(ANA));
-        assertThat(credentialList.get(0).model.get(CredentialProperties.FAVICON), is(nullValue()));
+        assertThat(credentialList.get(0).type, is(ItemType.CREDENTIAL));
+        assertThat(credentialList.get(0).model.get(CREDENTIAL), is(ANA));
+        assertThat(credentialList.get(0).model.get(FAVICON), is(nullValue()));
 
         // Showing the sheet a second time should replace all changed credentials.
         mMediator.showCredentials(TEST_URL, true, Collections.singletonList(BOB));
-        credentialList = mModel.get(CREDENTIAL_LIST);
+        credentialList = mModel.get(SHEET_ITEMS);
         // TODO(https://crbug.com/1013209): Simplify this after adding equals to ModelList.
         assertThat(credentialList.size(), is(1));
-        assertThat(credentialList.get(0).type, is(DEFAULT_ITEM_TYPE));
-        assertThat(credentialList.get(0).model.get(CredentialProperties.CREDENTIAL), is(BOB));
-        assertThat(credentialList.get(0).model.get(CredentialProperties.FAVICON), is(nullValue()));
+        assertThat(credentialList.get(0).type, is(ItemType.CREDENTIAL));
+        assertThat(credentialList.get(0).model.get(CREDENTIAL), is(BOB));
+        assertThat(credentialList.get(0).model.get(FAVICON), is(nullValue()));
     }
 
     @Test
@@ -162,7 +167,10 @@
     @Test
     public void testCallsCallbackAndHidesOnSelectingItem() {
         mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL));
-        mMediator.onSelectItemAt(1);
+        assertThat(mModel.get(VISIBLE), is(true));
+        assertNotNull(mModel.get(SHEET_ITEMS).get(1).model.get(ON_CLICK_LISTENER));
+
+        mModel.get(SHEET_ITEMS).get(1).model.get(ON_CLICK_LISTENER).onResult(CARL);
         verify(mMockDelegate).onCredentialSelected(CARL);
         assertThat(mModel.get(VISIBLE), is(false));
     }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 8776b47..8990c66 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -381,6 +381,7 @@
     "//components/sync_user_events",
     "//components/translate/content/browser",
     "//content/public/browser",
+    "//mojo/public/cpp/bindings",
   ]
   deps = [
     "//base",
@@ -2608,6 +2609,8 @@
       "views/apps/app_info_dialog/app_info_permissions_panel.h",
       "views/apps/app_info_dialog/app_info_summary_panel.cc",
       "views/apps/app_info_dialog/app_info_summary_panel.h",
+      "views/apps/app_uninstall_dialog_view.cc",
+      "views/apps/app_uninstall_dialog_view.h",
       "views/apps/chrome_native_app_window_views.cc",
       "views/apps/chrome_native_app_window_views.h",
       "views/autofill/autofill_bubble_handler_impl.cc",
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
index bfb5219f..76d6b13 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
@@ -14,6 +14,7 @@
 #include "base/command_line.h"
 #include "base/task/post_task.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/night_light/night_light_client.h"
 #include "chrome/browser/chromeos/policy/display_resolution_handler.h"
diff --git a/chrome/browser/ui/ash/ime_controller_client.cc b/chrome/browser/ui/ash/ime_controller_client.cc
index ddae5fe9..3305015 100644
--- a/chrome/browser/ui/ash/ime_controller_client.cc
+++ b/chrome/browser/ui/ash/ime_controller_client.cc
@@ -31,7 +31,7 @@
 }  // namespace
 
 ImeControllerClient::ImeControllerClient(InputMethodManager* manager)
-    : input_method_manager_(manager), binding_(this) {
+    : input_method_manager_(manager) {
   DCHECK(input_method_manager_);
   input_method_manager_->AddObserver(this);
   input_method_manager_->AddImeMenuObserver(this);
@@ -59,14 +59,14 @@
 
 void ImeControllerClient::Init() {
   // Connect to the controller in ash.
-  content::GetSystemConnector()->BindInterface(ash::mojom::kServiceName,
-                                               &ime_controller_ptr_);
+  content::GetSystemConnector()->Connect(
+      ash::mojom::kServiceName, ime_controller_.BindNewPipeAndPassReceiver());
   BindAndSetClient();
 }
 
 void ImeControllerClient::InitForTesting(
-    ash::mojom::ImeControllerPtr controller) {
-  ime_controller_ptr_ = std::move(controller);
+    mojo::PendingRemote<ash::mojom::ImeController> controller) {
+  ime_controller_.Bind(std::move(controller));
   BindAndSetClient();
 }
 
@@ -76,7 +76,7 @@
 }
 
 void ImeControllerClient::SetImesManagedByPolicy(bool managed) {
-  ime_controller_ptr_->SetImesManagedByPolicy(managed);
+  ime_controller_->SetImesManagedByPolicy(managed);
 }
 
 // ash::mojom::ImeControllerClient:
@@ -159,7 +159,7 @@
 
   // Mojo call to Ash to show the mode indicator view with the given anchor
   // bounds and short name.
-  ime_controller_ptr_->ShowModeIndicator(anchor_bounds, short_name);
+  ime_controller_->ShowModeIndicator(anchor_bounds, short_name);
 }
 
 // chromeos::input_method::InputMethodManager::Observer:
@@ -173,7 +173,7 @@
 
 // chromeos::input_method::InputMethodManager::ImeMenuObserver:
 void ImeControllerClient::ImeMenuActivationChanged(bool is_active) {
-  ime_controller_ptr_->ShowImeMenuOnShelf(is_active);
+  ime_controller_->ShowImeMenuOnShelf(is_active);
 }
 
 void ImeControllerClient::ImeMenuListChanged() {
@@ -192,28 +192,28 @@
 
 // chromeos::input_method::ImeKeyboard::Observer:
 void ImeControllerClient::OnCapsLockChanged(bool enabled) {
-  ime_controller_ptr_->UpdateCapsLockState(enabled);
+  ime_controller_->UpdateCapsLockState(enabled);
 }
 
 void ImeControllerClient::OnLayoutChanging(const std::string& layout_name) {
-  ime_controller_ptr_->OnKeyboardLayoutNameChanged(layout_name);
+  ime_controller_->OnKeyboardLayoutNameChanged(layout_name);
 }
 
 void ImeControllerClient::FlushMojoForTesting() {
-  ime_controller_ptr_.FlushForTesting();
+  ime_controller_.FlushForTesting();
 }
 
 void ImeControllerClient::BindAndSetClient() {
-  ash::mojom::ImeControllerClientPtr client;
-  binding_.Bind(mojo::MakeRequest(&client));
-  ime_controller_ptr_->SetClient(std::move(client));
+  mojo::PendingRemote<ash::mojom::ImeControllerClient> client;
+  receiver_.Bind(client.InitWithNewPipeAndPassReceiver());
+  ime_controller_->SetClient(std::move(client));
 
   // Now that the bridge is established, flush state from observed objects to
   // the ImeController, now that it will hear it.
   input_method_manager_->NotifyObserversImeExtraInputStateChange();
   if (const chromeos::input_method::ImeKeyboard* keyboard =
           input_method_manager_->GetImeKeyboard()) {
-    ime_controller_ptr_->OnKeyboardLayoutNameChanged(
+    ime_controller_->OnKeyboardLayoutNameChanged(
         keyboard->GetCurrentKeyboardLayoutName());
   }
 }
@@ -235,9 +235,9 @@
       input_method_manager_->GetActiveIMEState().get();
   if (!state) {
     const std::string empty_ime_id;
-    ime_controller_ptr_->RefreshIme(empty_ime_id,
-                                    std::vector<ash::mojom::ImeInfoPtr>(),
-                                    std::vector<ash::mojom::ImeMenuItemPtr>());
+    ime_controller_->RefreshIme(empty_ime_id,
+                                std::vector<ash::mojom::ImeInfoPtr>(),
+                                std::vector<ash::mojom::ImeMenuItemPtr>());
     return;
   }
 
@@ -262,8 +262,8 @@
     ash_item->checked = menu_item.is_selection_item_checked;
     ash_menu_items.push_back(std::move(ash_item));
   }
-  ime_controller_ptr_->RefreshIme(current_ime_id, std::move(available_imes),
-                                  std::move(ash_menu_items));
+  ime_controller_->RefreshIme(current_ime_id, std::move(available_imes),
+                              std::move(ash_menu_items));
 }
 
 void ImeControllerClient::OnExtraInputEnabledStateChange(
@@ -271,8 +271,8 @@
     bool is_emoji_enabled,
     bool is_handwriting_enabled,
     bool is_voice_enabled) {
-  if (ime_controller_ptr_) {
-    ime_controller_ptr_->SetExtraInputOptionsEnabledState(
+  if (ime_controller_) {
+    ime_controller_->SetExtraInputOptionsEnabledState(
         is_extra_input_options_enabled, is_emoji_enabled,
         is_handwriting_enabled, is_voice_enabled);
   }
diff --git a/chrome/browser/ui/ash/ime_controller_client.h b/chrome/browser/ui/ash/ime_controller_client.h
index 611ad352..c0374b83 100644
--- a/chrome/browser/ui/ash/ime_controller_client.h
+++ b/chrome/browser/ui/ash/ime_controller_client.h
@@ -8,7 +8,9 @@
 #include "ash/public/mojom/ime_controller.mojom.h"
 #include "ash/public/mojom/ime_info.mojom-forward.h"
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "ui/base/ime/chromeos/ime_keyboard.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
 #include "ui/chromeos/ime/input_method_menu_manager.h"
@@ -29,7 +31,8 @@
   void Init();
 
   // Tests can shim in a mock mojo interface for the ash controller.
-  void InitForTesting(ash::mojom::ImeControllerPtr controller);
+  void InitForTesting(
+      mojo::PendingRemote<ash::mojom::ImeController> controller);
 
   static ImeControllerClient* Get();
 
@@ -91,10 +94,10 @@
   chromeos::input_method::InputMethodManager* const input_method_manager_;
 
   // Binds this object to the mojo interface.
-  mojo::Binding<ash::mojom::ImeControllerClient> binding_;
+  mojo::Receiver<ash::mojom::ImeControllerClient> receiver_{this};
 
-  // ImeController interface in ash.
-  ash::mojom::ImeControllerPtr ime_controller_ptr_;
+  // ImeController remote in ash.
+  mojo::Remote<ash::mojom::ImeController> ime_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(ImeControllerClient);
 };
diff --git a/chrome/browser/ui/ash/ime_controller_client_unittest.cc b/chrome/browser/ui/ash/ime_controller_client_unittest.cc
index b0b49619..a530855 100644
--- a/chrome/browser/ui/ash/ime_controller_client_unittest.cc
+++ b/chrome/browser/ui/ash/ime_controller_client_unittest.cc
@@ -171,7 +171,7 @@
 TEST_F(ImeControllerClientTest, Construction) {
   std::unique_ptr<ImeControllerClient> client =
       std::make_unique<ImeControllerClient>(&input_method_manager_);
-  client->InitForTesting(ime_controller_.CreateInterfacePtr());
+  client->InitForTesting(ime_controller_.CreateRemote());
   EXPECT_EQ(1, input_method_manager_.add_observer_count_);
   EXPECT_EQ(1, input_method_manager_.add_menu_observer_count_);
 
@@ -182,7 +182,7 @@
 
 TEST_F(ImeControllerClientTest, SetImesManagedByPolicy) {
   ImeControllerClient client(&input_method_manager_);
-  client.InitForTesting(ime_controller_.CreateInterfacePtr());
+  client.InitForTesting(ime_controller_.CreateRemote());
 
   client.SetImesManagedByPolicy(true);
   client.FlushMojoForTesting();
@@ -191,7 +191,7 @@
 
 TEST_F(ImeControllerClientTest, CapsLock) {
   ImeControllerClient client(&input_method_manager_);
-  client.InitForTesting(ime_controller_.CreateInterfacePtr());
+  client.InitForTesting(ime_controller_.CreateRemote());
 
   client.OnCapsLockChanged(true);
   client.FlushMojoForTesting();
@@ -204,7 +204,7 @@
 
 TEST_F(ImeControllerClientTest, LayoutName) {
   ImeControllerClient client(&input_method_manager_);
-  client.InitForTesting(ime_controller_.CreateInterfacePtr());
+  client.InitForTesting(ime_controller_.CreateRemote());
 
   client.OnLayoutChanging("us(dvorak)");
   client.FlushMojoForTesting();
@@ -217,7 +217,7 @@
 
 TEST_F(ImeControllerClientTest, ExtraInputEnabledStateChange) {
   ImeControllerClient client(&input_method_manager_);
-  client.InitForTesting(ime_controller_.CreateInterfacePtr());
+  client.InitForTesting(ime_controller_.CreateRemote());
 
   client.OnExtraInputEnabledStateChange(true, true, false, false);
   client.FlushMojoForTesting();
@@ -243,7 +243,7 @@
 
 TEST_F(ImeControllerClientTest, ShowImeMenuOnShelf) {
   ImeControllerClient client(&input_method_manager_);
-  client.InitForTesting(ime_controller_.CreateInterfacePtr());
+  client.InitForTesting(ime_controller_.CreateRemote());
 
   client.ImeMenuActivationChanged(true);
   client.FlushMojoForTesting();
@@ -258,7 +258,7 @@
   ui::IMEBridge::Get()->SetCandidateWindowHandler(mock_candidate_window.get());
 
   ImeControllerClient client(&input_method_manager_);
-  client.InitForTesting(ime_controller_.CreateInterfacePtr());
+  client.InitForTesting(ime_controller_.CreateRemote());
 
   // Simulate a switch to IME 2.
   input_method_manager_.state_->current_ime_id_ = "id2";
@@ -289,7 +289,7 @@
 
 TEST_F(ImeControllerClientTest, NoActiveState) {
   ImeControllerClient client(&input_method_manager_);
-  client.InitForTesting(ime_controller_.CreateInterfacePtr());
+  client.InitForTesting(ime_controller_.CreateRemote());
 
   input_method_manager_.state_ = nullptr;
   client.InputMethodChanged(&input_method_manager_, nullptr /* profile */,
@@ -302,7 +302,7 @@
 
 TEST_F(ImeControllerClientTest, MenuItemChanged) {
   ImeControllerClient client(&input_method_manager_);
-  client.InitForTesting(ime_controller_.CreateInterfacePtr());
+  client.InitForTesting(ime_controller_.CreateRemote());
   const bool is_selection_item = true;
   InputMethodMenuItem item1("key1", "label1", is_selection_item,
                             true /* checked */);
diff --git a/chrome/browser/ui/ash/test_ime_controller.cc b/chrome/browser/ui/ash/test_ime_controller.cc
index 40a8beb8..54d6ff1 100644
--- a/chrome/browser/ui/ash/test_ime_controller.cc
+++ b/chrome/browser/ui/ash/test_ime_controller.cc
@@ -10,16 +10,19 @@
 
 #include "ash/public/mojom/ime_info.mojom.h"
 
-TestImeController::TestImeController() : binding_(this) {}
+TestImeController::TestImeController() = default;
+
 TestImeController::~TestImeController() = default;
 
-ash::mojom::ImeControllerPtr TestImeController::CreateInterfacePtr() {
-  ash::mojom::ImeControllerPtr ptr;
-  binding_.Bind(mojo::MakeRequest(&ptr));
-  return ptr;
+mojo::PendingRemote<ash::mojom::ImeController>
+TestImeController::CreateRemote() {
+  mojo::PendingRemote<ash::mojom::ImeController> remote;
+  receiver_.Bind(remote.InitWithNewPipeAndPassReceiver());
+  return remote;
 }
 
-void TestImeController::SetClient(ash::mojom::ImeControllerClientPtr client) {}
+void TestImeController::SetClient(
+    mojo::PendingRemote<ash::mojom::ImeControllerClient> client) {}
 
 void TestImeController::RefreshIme(
     const std::string& current_ime_id,
diff --git a/chrome/browser/ui/ash/test_ime_controller.h b/chrome/browser/ui/ash/test_ime_controller.h
index b458ee5..5b4e1a4 100644
--- a/chrome/browser/ui/ash/test_ime_controller.h
+++ b/chrome/browser/ui/ash/test_ime_controller.h
@@ -11,18 +11,20 @@
 
 #include "ash/public/mojom/ime_controller.mojom.h"
 #include "ash/public/mojom/ime_info.mojom-forward.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 class TestImeController : ash::mojom::ImeController {
  public:
   TestImeController();
   ~TestImeController() override;
 
-  // Returns a mojo interface pointer bound to this object.
-  ash::mojom::ImeControllerPtr CreateInterfacePtr();
+  // Returns a mojo remote for this object.
+  mojo::PendingRemote<ash::mojom::ImeController> CreateRemote();
 
   // ash::mojom::ImeController:
-  void SetClient(ash::mojom::ImeControllerClientPtr client) override;
+  void SetClient(
+      mojo::PendingRemote<ash::mojom::ImeControllerClient> client) override;
   void RefreshIme(const std::string& current_ime_id,
                   std::vector<ash::mojom::ImeInfoPtr> available_imes,
                   std::vector<ash::mojom::ImeMenuItemPtr> menu_items) override;
@@ -52,7 +54,7 @@
   bool is_voice_enabled_ = false;
 
  private:
-  mojo::Binding<ash::mojom::ImeController> binding_;
+  mojo::Receiver<ash::mojom::ImeController> receiver_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TestImeController);
 };
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index ea919c4..371571a 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -1212,7 +1212,7 @@
   return true;
 }
 
-blink::WebSecurityStyle Browser::GetSecurityStyle(
+blink::SecurityStyle Browser::GetSecurityStyle(
     WebContents* web_contents,
     content::SecurityStyleExplanations* security_style_explanations) {
   SecurityStateTabHelper* helper =
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 82e2ee1..7d5c48fe 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -549,7 +549,7 @@
   bool CanDragEnter(content::WebContents* source,
                     const content::DropData& data,
                     blink::WebDragOperationsMask operations_allowed) override;
-  blink::WebSecurityStyle GetSecurityStyle(
+  blink::SecurityStyle GetSecurityStyle(
       content::WebContents* web_contents,
       content::SecurityStyleExplanations* security_style_explanations) override;
   std::unique_ptr<content::BluetoothChooser> RunBluetoothChooser(
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
index 4cba694f..f08a848 100644
--- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
+++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
@@ -21,6 +21,7 @@
 #include "chrome/browser/apps/launch_service/launch_service.h"
 #include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/ui/libgtkui/select_file_dialog_impl_gtk.cc b/chrome/browser/ui/libgtkui/select_file_dialog_impl_gtk.cc
index 4da1b5f..5be7e3e0 100644
--- a/chrome/browser/ui/libgtkui/select_file_dialog_impl_gtk.cc
+++ b/chrome/browser/ui/libgtkui/select_file_dialog_impl_gtk.cc
@@ -200,7 +200,7 @@
       host->ReleaseCapture();
       std::unique_ptr<base::OnceClosure> callback =
           std::make_unique<base::OnceClosure>(
-              views::DesktopWindowTreeHostX11::GetHostForXID(
+              views::DesktopWindowTreeHostLinux::GetHostForWidget(
                   host->GetAcceleratedWidget())
                   ->DisableEventListening());
       // OnFilePickerDestroy() is called when |dialog| destroyed, which allows
diff --git a/chrome/browser/ui/pdf/adobe_reader_info_win.cc b/chrome/browser/ui/pdf/adobe_reader_info_win.cc
index f9db587..c3e20f678 100644
--- a/chrome/browser/ui/pdf/adobe_reader_info_win.cc
+++ b/chrome/browser/ui/pdf/adobe_reader_info_win.cc
@@ -12,6 +12,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/file_version_info.h"
+#include "base/files/file_path.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/ui/tab_sharing/OWNERS b/chrome/browser/ui/tab_sharing/OWNERS
index eb004e66..f718b9d9 100644
--- a/chrome/browser/ui/tab_sharing/OWNERS
+++ b/chrome/browser/ui/tab_sharing/OWNERS
@@ -1,2 +1,4 @@
 marinaciocea@chromium.org
 guidou@chromium.org
+
+# COMPONENT: Blink>GetUserMedia>Desktop
diff --git a/chrome/browser/ui/views/apps/app_uninstall_dialog_view.cc b/chrome/browser/ui/views/apps/app_uninstall_dialog_view.cc
new file mode 100644
index 0000000..349be48
--- /dev/null
+++ b/chrome/browser/ui/views/apps/app_uninstall_dialog_view.cc
@@ -0,0 +1,230 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/apps/app_uninstall_dialog_view.h"
+
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "chrome/browser/ui/views/chrome_typography.h"
+#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
+#include "chrome/grit/chromium_strings.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/constrained_window/constrained_window_views.h"
+#include "components/strings/grit/components_strings.h"
+#include "components/url_formatter/elide_url.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/manifest_url_handlers.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/image/image_skia_operations.h"
+#include "ui/views/controls/button/checkbox.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#endif
+
+// static
+void apps::UninstallDialog::UiBase::Create(
+    Profile* profile,
+    apps::mojom::AppType app_type,
+    const std::string& app_id,
+    gfx::ImageSkia image,
+    apps::UninstallDialog* uninstall_dialog) {
+  new AppUninstallDialogView(profile, app_type, app_id, image,
+                             uninstall_dialog);
+}
+
+AppUninstallDialogView::AppUninstallDialogView(
+    Profile* profile,
+    apps::mojom::AppType app_type,
+    const std::string& app_id,
+    gfx::ImageSkia image,
+    apps::UninstallDialog* uninstall_dialog)
+    : apps::UninstallDialog::UiBase(image, uninstall_dialog),
+      BubbleDialogDelegateView(nullptr, views::BubbleBorder::NONE) {
+  ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
+  SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical, gfx::Insets(),
+      provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL)));
+
+  // Add margins for the icon plus the icon-title padding so that the dialog
+  // contents align with the title text.
+  set_margins(
+      margins() +
+      gfx::Insets(0, margins().left() + apps::UninstallDialog::kSizeHintInDip,
+                  0, 0));
+
+  InitializeView(profile, app_type, app_id);
+  constrained_window::CreateBrowserModalDialogViews(this, nullptr)->Show();
+}
+
+bool AppUninstallDialogView::Cancel() {
+  return Close();
+}
+
+bool AppUninstallDialogView::Accept() {
+  const bool clear_site_data =
+      clear_site_data_checkbox_ && clear_site_data_checkbox_->GetChecked();
+  const bool report_abuse_checkbox =
+      report_abuse_checkbox_ && report_abuse_checkbox_->GetChecked();
+  uninstall_dialog()->OnDialogClosed(true /* uninstall */, clear_site_data,
+                                     report_abuse_checkbox);
+  return true;
+}
+
+bool AppUninstallDialogView::Close() {
+  uninstall_dialog()->OnDialogClosed(false /* uninstall */,
+                                     false /* clear_site_data */,
+                                     false /* report_abuse */);
+  return true;
+}
+
+gfx::Size AppUninstallDialogView::CalculatePreferredSize() const {
+  const int default_width = views::LayoutProvider::Get()->GetDistanceMetric(
+                                DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH) -
+                            margins().width();
+  return gfx::Size(default_width, GetHeightForWidth(default_width));
+}
+
+base::string16 AppUninstallDialogView::GetDialogButtonLabel(
+    ui::DialogButton button) const {
+  return button == ui::DIALOG_BUTTON_CANCEL ? cancel_button_text_
+                                            : confirm_button_text_;
+}
+
+ui::ModalType AppUninstallDialogView::GetModalType() const {
+  return ui::MODAL_TYPE_WINDOW;
+}
+
+gfx::ImageSkia AppUninstallDialogView::GetWindowIcon() {
+  return image();
+}
+
+base::string16 AppUninstallDialogView::GetWindowTitle() const {
+  return window_title_;
+}
+
+bool AppUninstallDialogView::ShouldShowCloseButton() const {
+  return false;
+}
+
+bool AppUninstallDialogView::ShouldShowWindowIcon() const {
+  return true;
+}
+
+void AppUninstallDialogView::AddMultiLineLabel(
+    views::View* parent,
+    const base::string16& label_text) {
+  auto* label =
+      parent->AddChildView(std::make_unique<views::Label>(label_text));
+  label->SetMultiLine(true);
+  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  label->SetAllowCharacterBreak(true);
+}
+
+void AppUninstallDialogView::InitializeViewForExtension(
+    Profile* profile,
+    const std::string& app_id) {
+  const extensions::Extension* extension =
+      extensions::ExtensionRegistry::Get(profile)->GetInstalledExtension(
+          app_id);
+  DCHECK(extension);
+
+  window_title_ =
+      l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_UNINSTALL_TITLE,
+                                 base::UTF8ToUTF16(extension->name()));
+
+  confirm_button_text_ =
+      l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON);
+
+  if (extensions::ManifestURL::UpdatesFromGallery(extension)) {
+    auto report_abuse_checkbox = std::make_unique<views::Checkbox>(
+        l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_UNINSTALL_REPORT_ABUSE));
+    report_abuse_checkbox->SetMultiLine(true);
+    report_abuse_checkbox_ = AddChildView(std::move(report_abuse_checkbox));
+  } else if (extension->from_bookmark()) {
+    auto clear_site_data_checkbox =
+        std::make_unique<views::Checkbox>(l10n_util::GetStringFUTF16(
+            IDS_EXTENSION_UNINSTALL_PROMPT_REMOVE_DATA_CHECKBOX,
+            url_formatter::FormatUrlForSecurityDisplay(
+                extensions::AppLaunchInfo::GetFullLaunchURL(extension),
+                url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC)));
+    clear_site_data_checkbox->SetMultiLine(true);
+    clear_site_data_checkbox_ =
+        AddChildView(std::move(clear_site_data_checkbox));
+  }
+}
+
+#if defined(OS_CHROMEOS)
+void AppUninstallDialogView::InitializeViewForArcApp(
+    Profile* profile,
+    const std::string& app_id) {
+  ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile);
+  DCHECK(arc_prefs);
+
+  std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
+      arc_prefs->GetApp(app_id);
+  DCHECK(arc_prefs);
+
+  window_title_ = l10n_util::GetStringUTF16(
+      app_info->shortcut ? IDS_EXTENSION_UNINSTALL_PROMPT_TITLE
+                         : IDS_APP_UNINSTALL_PROMPT_TITLE);
+
+  base::string16 heading_text = l10n_util::GetStringFUTF16(
+      app_info->shortcut ? IDS_EXTENSION_UNINSTALL_PROMPT_HEADING
+                         : IDS_NON_PLATFORM_APP_UNINSTALL_PROMPT_HEADING,
+      base::UTF8ToUTF16(app_info->name));
+  base::string16 subheading_text;
+  if (!app_info->shortcut) {
+    subheading_text = l10n_util::GetStringUTF16(
+        IDS_ARC_APP_UNINSTALL_PROMPT_DATA_REMOVAL_WARNING);
+  }
+
+  confirm_button_text_ = l10n_util::GetStringUTF16(
+      app_info->shortcut ? IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON
+                         : IDS_EXTENSION_PROMPT_UNINSTALL_APP_BUTTON);
+
+  auto* text_container = AddChildView(std::make_unique<views::View>());
+  auto* text_container_layout =
+      SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::Orientation::kVertical));
+  text_container_layout->set_main_axis_alignment(
+      views::BoxLayout::MainAxisAlignment::kCenter);
+  text_container_layout->set_cross_axis_alignment(
+      views::BoxLayout::CrossAxisAlignment::kStart);
+
+  AddMultiLineLabel(text_container, heading_text);
+  if (!subheading_text.empty())
+    AddMultiLineLabel(text_container, subheading_text);
+}
+#endif
+
+void AppUninstallDialogView::InitializeView(Profile* profile,
+                                            apps::mojom::AppType app_type,
+                                            const std::string& app_id) {
+  cancel_button_text_ = l10n_util::GetStringUTF16(IDS_CANCEL);
+
+  switch (app_type) {
+    case apps::mojom::AppType::kUnknown:
+    case apps::mojom::AppType::kBuiltIn:
+      NOTREACHED();
+      break;
+    case apps::mojom::AppType::kArc:
+#if defined(OS_CHROMEOS)
+      InitializeViewForArcApp(profile, app_id);
+#endif
+      break;
+    case apps::mojom::AppType::kCrostini:
+      NOTREACHED();
+      break;
+    case apps::mojom::AppType::kExtension:
+    case apps::mojom::AppType::kWeb:
+      InitializeViewForExtension(profile, app_id);
+      break;
+  }
+}
diff --git a/chrome/browser/ui/views/apps/app_uninstall_dialog_view.h b/chrome/browser/ui/views/apps/app_uninstall_dialog_view.h
new file mode 100644
index 0000000..2005972
--- /dev/null
+++ b/chrome/browser/ui/views/apps/app_uninstall_dialog_view.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_APPS_APP_UNINSTALL_DIALOG_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_APPS_APP_UNINSTALL_DIALOG_VIEW_H_
+
+#include <memory>
+#include "base/macros.h"
+#include "chrome/browser/apps/app_service/uninstall_dialog.h"
+#include "chrome/services/app_service/public/mojom/types.mojom.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+
+class Profile;
+
+namespace views {
+class Checkbox;
+}  // namespace views
+
+namespace gfx {
+class ImageSkia;
+}
+
+// Currently, app uninstallation on Chrome OS invokes a specific dialog per app
+// type:
+// - Chrome Apps / PWAs:
+// https://cs.chromium.org/chromium/src/chrome/browser/ui/app_list/extension_uninstaller.h?q=extensionuninstaller&sq=package:chromium&l=17
+// - ARC apps:
+// https://cs.chromium.org/chromium/src/chrome/browser/ui/app_list/arc/arc_app_dialog.h?q=arcappunin&sq=package:chromium&l=21
+// - Crostini:
+// https://cs.chromium.org/chromium/src/chrome/browser/chromeos/crostini/crostini_util.h?type=cs&q=crostiniuninstall&sq=package:chromium&g=0&l=131
+//
+// There are 3 separate views for app uninstalling, which are subtly different
+// from each other.
+//
+// This class combines the above three specific dialogs, and generates the
+// correct UI based on the app type. Once the user has confirmed the uninstall,
+// this class calls the parent class apps::UninstallDialog::UiBase to notify
+// AppService, which transfers control to the publisher to uninstall the app.
+//
+// TODO(crbug.com/1009248):
+// 1. Add Crostini uninstall function.
+// 2. Add an interface to the uninstall, like what is done by
+// extension_uninstall_dialog_->ConfirmUninstallByExtension.
+class AppUninstallDialogView : public apps::UninstallDialog::UiBase,
+                               views::BubbleDialogDelegateView {
+ public:
+  AppUninstallDialogView(Profile* profile,
+                         apps::mojom::AppType app_type,
+                         const std::string& app_id,
+                         gfx::ImageSkia image,
+                         apps::UninstallDialog* uninstall_dialog);
+  ~AppUninstallDialogView() override = default;
+
+  // views::BubbleDialogDelegateView:
+  bool Cancel() override;
+  bool Accept() override;
+  bool Close() override;
+  gfx::Size CalculatePreferredSize() const override;
+  base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
+  ui::ModalType GetModalType() const override;
+  gfx::ImageSkia GetWindowIcon() override;
+  base::string16 GetWindowTitle() const override;
+  bool ShouldShowCloseButton() const override;
+  bool ShouldShowWindowIcon() const override;
+
+ private:
+  void AddMultiLineLabel(views::View* parent, const base::string16& label_text);
+  void InitializeViewForExtension(Profile* profile, const std::string& app_id);
+#if defined(OS_CHROMEOS)
+  void InitializeViewForArcApp(Profile* profile, const std::string& app_id);
+#endif
+  void InitializeView(Profile* profile,
+                      apps::mojom::AppType app_type,
+                      const std::string& app_id);
+
+  views::Checkbox* report_abuse_checkbox_ = nullptr;
+  views::Checkbox* clear_site_data_checkbox_ = nullptr;
+
+  // TODO(crbug.com/1009248): Remove these fields to use the consistent title
+  // and button.
+  base::string16 window_title_;
+  base::string16 confirm_button_text_;
+  base::string16 cancel_button_text_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppUninstallDialogView);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_APPS_APP_UNINSTALL_DIALOG_VIEW_H_
diff --git a/chrome/browser/ui/views/autofill/payments/local_card_migration_browsertest.cc b/chrome/browser/ui/views/autofill/payments/local_card_migration_browsertest.cc
index f08715f..31062c7 100644
--- a/chrome/browser/ui/views/autofill/payments/local_card_migration_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/payments/local_card_migration_browsertest.cc
@@ -516,7 +516,7 @@
             GetLocalCardMigrationOfferBubbleViews());
     CHECK(local_card_migration_bubble_views);
     return local_card_migration_bubble_views->GetBubbleFrameView()
-        ->GetCloseButtonForTest();
+        ->GetCloseButtonForTesting();
   }
 
   views::View* GetCardListView() {
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
index d0e126ca..3e3e7ec 100644
--- a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
@@ -713,8 +713,8 @@
     SaveCardBubbleViews* save_card_bubble_views = GetSaveCardBubbleViews();
     DCHECK(save_card_bubble_views);
     ResetEventWaiterForSequence({DialogEvent::BUBBLE_CLOSED});
-    ClickOnDialogViewAndWait(
-        save_card_bubble_views->GetBubbleFrameView()->GetCloseButtonForTest());
+    ClickOnDialogViewAndWait(save_card_bubble_views->GetBubbleFrameView()
+                                 ->GetCloseButtonForTesting());
     DCHECK(!GetSaveCardBubbleViews());
   }
 
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
index 4d7da7b2..912ee40 100644
--- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
+++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
@@ -34,6 +34,7 @@
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "content/public/browser/system_connector.h"
 #include "content/public/test/browser_test_utils.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/dns/mock_host_resolver.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/aura/window.h"
@@ -791,9 +792,10 @@
       display::Display::ROTATE_270, display::Display::ROTATE_0,
   };
 
-  ash::mojom::CrosDisplayConfigControllerPtr cros_display_config;
-  content::GetSystemConnector()->BindInterface(ash::mojom::kServiceName,
-                                               &cros_display_config);
+  mojo::Remote<ash::mojom::CrosDisplayConfigController> cros_display_config;
+  content::GetSystemConnector()->Connect(
+      ash::mojom::kServiceName,
+      cros_display_config.BindNewPipeAndPassReceiver());
   ash::mojom::CrosDisplayConfigControllerAsyncWaiter waiter_for(
       cros_display_config.get());
   std::vector<ash::mojom::DisplayUnitInfoPtr> info_list;
diff --git a/chrome/browser/ui/views/location_bar/cookie_controls_bubble_view.cc b/chrome/browser/ui/views/location_bar/cookie_controls_bubble_view.cc
index 0dc808d..59daa1c 100644
--- a/chrome/browser/ui/views/location_bar/cookie_controls_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/cookie_controls_bubble_view.cc
@@ -61,7 +61,8 @@
     OnBlockedCookiesCountChanged(blocked_cookies);
     return;
   }
-  intermediate_step_ = IntermediateStep::kNone;
+  if (new_status != CookieControlsController::Status::kEnabled)
+    intermediate_step_ = IntermediateStep::kNone;
   status_ = new_status;
   blocked_cookies_ = blocked_cookies;
   UpdateUi();
@@ -268,9 +269,8 @@
   } else {
     DCHECK_EQ(status_, CookieControlsController::Status::kDisabledForSite);
     DCHECK_EQ(intermediate_step_, IntermediateStep::kNone);
-    controller_->OnCookieBlockingEnabledForSite(true);
     intermediate_step_ = IntermediateStep::kBlockingIsOn;
-    UpdateUi();
+    controller_->OnCookieBlockingEnabledForSite(true);
   }
   return false;
 }
diff --git a/chrome/browser/ui/views/location_bar/cookie_controls_icon_view.cc b/chrome/browser/ui/views/location_bar/cookie_controls_icon_view.cc
index 95b616f4..6151b2b 100644
--- a/chrome/browser/ui/views/location_bar/cookie_controls_icon_view.cc
+++ b/chrome/browser/ui/views/location_bar/cookie_controls_icon_view.cc
@@ -96,8 +96,8 @@
 
 const gfx::VectorIcon& CookieControlsIconView::GetVectorIcon() const {
   if (status_ == CookieControlsController::Status::kDisabledForSite)
-    return kShieldOffIcon;
-  return has_blocked_cookies_ ? kShieldDotIcon : kShieldOutlineIcon;
+    return kEyeIcon;
+  return has_blocked_cookies_ ? kEyeCrossedDotIcon : kEyeCrossedIcon;
 }
 
 base::string16 CookieControlsIconView::GetTextForTooltipAndAccessibleName()
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
index b52f59e..7526c2a4 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -31,8 +31,8 @@
 #include "ui/views/animation/ink_drop_ripple.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
+#include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/controls/image_view.h"
-#include "ui/views/view_class_properties.h"
 #include "ui/views/widget/widget.h"
 
 using MD = ui::MaterialDesignController;
@@ -120,6 +120,23 @@
 }
 
 //////////////////////////////////////////////////////////////////
+// HighlightPathGenerator class
+
+class IconLabelBubbleView::HighlightPathGenerator
+    : public views::HighlightPathGenerator {
+ public:
+  HighlightPathGenerator() = default;
+
+  // views::HighlightPathGenerator:
+  SkPath GetHighlightPath(const views::View* view) override {
+    return static_cast<const IconLabelBubbleView*>(view)->GetHighlightPath();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HighlightPathGenerator);
+};
+
+//////////////////////////////////////////////////////////////////
 // IconLabelBubbleView class
 
 IconLabelBubbleView::IconLabelBubbleView(const gfx::FontList& font_list)
@@ -136,6 +153,9 @@
   set_ink_drop_highlight_opacity(
       GetOmniboxStateOpacity(OmniboxPartState::HOVERED));
 
+  views::HighlightPathGenerator::Install(
+      this, std::make_unique<HighlightPathGenerator>());
+
   UpdateBorder();
 
   set_notify_enter_exit_on_child(true);
@@ -264,7 +284,10 @@
   separator_view_->SetBounds(separator_x, separator_bounds.y(), separator_width,
                              separator_height);
 
-  UpdateHighlightPath();
+  if (focus_ring()) {
+    focus_ring()->Layout();
+    focus_ring()->SchedulePaint();
+  }
 }
 
 bool IconLabelBubbleView::OnMousePressed(const ui::MouseEvent& event) {
@@ -522,7 +545,7 @@
   GetInkDrop()->SetShowHighlightOnFocus(false);
 }
 
-void IconLabelBubbleView::UpdateHighlightPath() {
+SkPath IconLabelBubbleView::GetHighlightPath() const {
   gfx::Rect highlight_bounds = GetLocalBounds();
   if (ShouldShowSeparator())
     highlight_bounds.Inset(0, 0, GetEndPaddingWithSeparator(), 0);
@@ -531,13 +554,7 @@
   const float corner_radius = highlight_bounds.height() / 2.f;
   const SkRect rect = RectToSkRect(highlight_bounds);
 
-  SkPath path;
-  path.addRoundRect(rect, corner_radius, corner_radius);
-  SetProperty(views::kHighlightPathKey, path);
-  if (focus_ring()) {
-    focus_ring()->Layout();
-    focus_ring()->SchedulePaint();
-  }
+  return SkPath().addRoundRect(rect, corner_radius, corner_radius);
 }
 
 void IconLabelBubbleView::UpdateBorder() {
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
index c91c085..0b3c420 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
@@ -12,6 +12,7 @@
 #include "base/optional.h"
 #include "base/scoped_observer.h"
 #include "base/strings/string16.h"
+#include "third_party/skia/include/core/SkPath.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/material_design/material_design_controller_observer.h"
 #include "ui/gfx/geometry/insets.h"
@@ -188,6 +189,8 @@
   bool is_animation_paused() const { return is_animation_paused_; }
 
  private:
+  class HighlightPathGenerator;
+
   // Spacing between the image and the label.
   int GetInternalSpacing() const;
 
@@ -216,9 +219,9 @@
   // called directly, use AnimateOut() instead, which handles label visibility.
   void HideAnimation();
 
-  // Updates the highlight path for ink drops and focus rings using the current
-  // bounds and the separator visibility.
-  void UpdateHighlightPath();
+  // Gets the highlight path for ink drops and focus rings using the current
+  // bounds and separator visibility.
+  SkPath GetHighlightPath() const;
 
   // Sets the border padding around this view.
   void UpdateBorder();
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.cc b/chrome/browser/ui/views/profiles/profile_menu_view.cc
index c5af4529..f450f65 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view.cc
@@ -27,6 +27,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
@@ -133,6 +134,15 @@
 }
 #endif
 
+// Returns the number of browsers associated with |profile|.
+// Note: For regular profiles this includes incognito sessions.
+int CountBrowsersFor(Profile* profile) {
+  int browser_count = chrome::GetBrowserCount(profile);
+  if (!profile->IsOffTheRecord() && profile->HasOffTheRecordProfile())
+    browser_count += chrome::GetBrowserCount(profile->GetOffTheRecordProfile());
+  return browser_count;
+}
+
 }  // namespace
 
 // ProfileMenuView ---------------------------------------------------------
@@ -545,9 +555,10 @@
 }
 
 void ProfileMenuView::BuildFeatureButtons() {
+  Profile* profile = browser()->profile();
   signin::IdentityManager* identity_manager =
-      IdentityManagerFactory::GetForProfile(browser()->profile());
-  const bool is_guest = browser()->profile()->IsGuestSession();
+      IdentityManagerFactory::GetForProfile(profile);
+  const bool is_guest = profile->IsGuestSession();
   const bool has_unconsented_account =
       !is_guest && identity_manager->HasUnconsentedPrimaryAccount();
   const bool has_primary_account =
@@ -570,7 +581,8 @@
 
   AddFeatureButton(
       ImageForMenu(kCloseAllIcon),
-      l10n_util::GetStringUTF16(IDS_PROFILES_CLOSE_ALL_WINDOWS_BUTTON),
+      l10n_util::GetPluralStringFUTF16(IDS_PROFILES_CLOSE_X_WINDOWS_BUTTON,
+                                       CountBrowsersFor(profile)),
       base::BindRepeating(&ProfileMenuView::OnExitProfileButtonClicked,
                           base::Unretained(this)));
 
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
index 62e58d8..a7e74ee 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
@@ -723,8 +723,8 @@
                        ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0));
   }
 
-  ProfileMenuView* profile_menu_view() {
-    return static_cast<ProfileMenuView*>(
+  ProfileMenuViewBase* profile_menu_view() {
+    return static_cast<ProfileMenuViewBase*>(
         ProfileMenuViewBase::GetBubbleForTesting());
   }
 
@@ -907,9 +907,8 @@
         // there are no other buttons at the end.
         ProfileMenuViewBase::ActionableItem::kExitProfileButton};
 
-// TODO(crbug.com/1012167, 1014343): This crashes on Linux CFI bot.
 PROFILE_MENU_CLICK_TEST(kActionableItems_IncognitoProfile,
-                        DISABLED_ProfileMenuClickTest_IncognitoProfile) {
+                        ProfileMenuClickTest_IncognitoProfile) {
   SetTargetBrowser(CreateIncognitoBrowser(browser()->profile()));
 
   RunTest();
diff --git a/chrome/browser/ui/views/sharing/sharing_dialog_view.cc b/chrome/browser/ui/views/sharing/sharing_dialog_view.cc
index 716d6163..b0bd3c57 100644
--- a/chrome/browser/ui/views/sharing/sharing_dialog_view.cc
+++ b/chrome/browser/ui/views/sharing/sharing_dialog_view.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/sharing/sharing_dialog_view.h"
 
+#include "base/optional.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/app/vector_icons/vector_icons.h"
@@ -17,16 +18,20 @@
 #include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
 #include "chrome/browser/ui/views/hover_button.h"
 #include "components/sync_device_info/device_info.h"
+#include "components/url_formatter/elide_url.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/color_utils.h"
+#include "ui/gfx/font_list.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/strings/grit/ui_strings.h"
+#include "ui/views/background.h"
 #include "ui/views/border.h"
 #include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/controls/styled_label.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
+#include "url/origin.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/ui/page_action/page_action_icon_type.h"
@@ -93,6 +98,61 @@
   return label;
 }
 
+std::unique_ptr<views::View> MaybeCreateOriginView(
+    const SharingDialogData& data) {
+  if (!data.initiating_origin || !data.origin_text_id)
+    return nullptr;
+
+  auto label = std::make_unique<views::Label>(
+      l10n_util::GetStringFUTF16(data.origin_text_id,
+                                 url_formatter::FormatOriginForSecurityDisplay(
+                                     *data.initiating_origin)),
+      views::style::CONTEXT_LABEL, views::style::STYLE_SECONDARY);
+  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  label->SetElideBehavior(gfx::ELIDE_HEAD);
+  label->SetMultiLine(false);
+  label->SetFontList(label->font_list().DeriveWithSizeDelta(-2));
+
+  auto background_color =
+      ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor(
+          ui::NativeTheme::kColorId_BubbleFooterBackground);
+  label->SetBackgroundColor(background_color);
+  label->SetBackground(
+      views::CreateRoundedRectBackground(background_color, /*radius=*/8));
+
+  gfx::Insets insets =
+      ChromeLayoutProvider::Get()->GetDialogInsetsForContentType(views::TEXT,
+                                                                 views::TEXT);
+  gfx::Insets border_insets(4, insets.width() / 4, 4, insets.width() / 4);
+  gfx::Insets container_insets(insets.top(),
+                               insets.left() - border_insets.left(), 0,
+                               insets.right() - border_insets.right());
+  label->SetBorder(views::CreateEmptyBorder(border_insets));
+
+  auto container = std::make_unique<views::View>();
+  container->SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical, container_insets));
+  container->AddChildView(std::move(label));
+  return container;
+}
+
+std::unique_ptr<views::View> MaybeCreateImageView(int image_id) {
+  if (!image_id)
+    return nullptr;
+
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  const gfx::ImageSkia* image = rb.GetNativeImageNamed(image_id).ToImageSkia();
+  gfx::Size image_size(image->width(), image->height());
+  constexpr int kHeaderImageHeight = 100;
+  const int image_width = image->width() * kHeaderImageHeight / image->height();
+  image_size.SetToMin(gfx::Size(image_width, kHeaderImageHeight));
+
+  auto image_view = std::make_unique<NonAccessibleImageView>();
+  image_view->SetImageSize(image_size);
+  image_view->SetImage(*image);
+  return image_view;
+}
+
 }  // namespace
 
 SharingDialogView::SharingDialogView(views::View* anchor_view,
@@ -199,24 +259,23 @@
   int image_id = color_utils::IsDark(frame_view->GetBackgroundColor())
                      ? data_.header_image_dark
                      : data_.header_image_light;
-  if (!image_id) {
-    // Clear any previously set header image.
-    frame_view->SetHeaderView(nullptr);
-    return;
-  }
 
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  const gfx::ImageSkia* image = rb.GetNativeImageNamed(image_id).ToImageSkia();
-  gfx::Size image_size(image->width(), image->height());
-  constexpr int kHeaderImageHeight = 100;
-  const int image_width = image->width() * kHeaderImageHeight / image->height();
-  image_size.SetToMin(gfx::Size(image_width, kHeaderImageHeight));
+  std::unique_ptr<views::View> image_view = MaybeCreateImageView(image_id);
+  std::unique_ptr<views::View> origin_view = MaybeCreateOriginView(data_);
+  std::unique_ptr<views::View> header_view = std::make_unique<views::View>();
+  header_view->SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical));
 
-  auto image_view = std::make_unique<NonAccessibleImageView>();
-  image_view->SetImageSize(image_size);
-  image_view->SetImage(*image);
+  if (image_view)
+    header_view->AddChildView(std::move(image_view));
+  if (origin_view)
+    header_view->AddChildView(std::move(origin_view));
 
-  frame_view->SetHeaderView(std::move(image_view));
+  // Clear header if it has no content.
+  if (header_view->children().empty())
+    header_view = nullptr;
+
+  frame_view->SetHeaderView(std::move(header_view));
 }
 
 void SharingDialogView::AddedToWidget() {
diff --git a/chrome/browser/ui/views/sharing/sharing_dialog_view_unittest.cc b/chrome/browser/ui/views/sharing/sharing_dialog_view_unittest.cc
index 66b5e47..bb433285 100644
--- a/chrome/browser/ui/views/sharing/sharing_dialog_view_unittest.cc
+++ b/chrome/browser/ui/views/sharing/sharing_dialog_view_unittest.cc
@@ -20,6 +20,11 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/events/event_utils.h"
 #include "ui/strings/grit/ui_strings.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/bubble/bubble_frame_view.h"
+#include "ui/views/test/widget_test.h"
+#include "url/gurl.h"
+#include "url/origin.h"
 
 namespace {
 
@@ -211,3 +216,54 @@
   // Regression test for crbug.com/1001112
   dialog->OnThemeChanged();
 }
+
+TEST_F(SharingDialogViewTest, OriginViewShown) {
+  auto dialog_data = CreateDialogData(/*devices=*/1, /*apps=*/1);
+  dialog_data.origin_text_id =
+      IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_INITIATING_ORIGIN;
+  dialog_data.initiating_origin =
+      url::Origin::Create(GURL("https://example.com"));
+
+  views::test::WidgetTest::WidgetAutoclosePtr bubble_widget(
+      views::BubbleDialogDelegateView::CreateBubble(
+          CreateDialogView(std::move(dialog_data)).release()));
+
+  auto* frame_view = static_cast<views::BubbleFrameView*>(
+      bubble_widget->non_client_view()->frame_view());
+
+  EXPECT_NE(nullptr, frame_view->GetHeaderViewForTesting());
+}
+
+TEST_F(SharingDialogViewTest, OriginViewHiddenIfNoOrigin) {
+  auto dialog_data = CreateDialogData(/*devices=*/1, /*apps=*/1);
+  dialog_data.origin_text_id =
+      IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_INITIATING_ORIGIN;
+  // Do not set an origin.
+  dialog_data.initiating_origin = base::nullopt;
+
+  views::test::WidgetTest::WidgetAutoclosePtr bubble_widget(
+      views::BubbleDialogDelegateView::CreateBubble(
+          CreateDialogView(std::move(dialog_data)).release()));
+
+  auto* frame_view = static_cast<views::BubbleFrameView*>(
+      bubble_widget->non_client_view()->frame_view());
+
+  EXPECT_EQ(nullptr, frame_view->GetHeaderViewForTesting());
+}
+
+TEST_F(SharingDialogViewTest, OriginViewHiddenIfNoOriginText) {
+  auto dialog_data = CreateDialogData(/*devices=*/1, /*apps=*/1);
+  // Do not set an origin text.
+  dialog_data.origin_text_id = 0;
+  dialog_data.initiating_origin =
+      url::Origin::Create(GURL("https://example.com"));
+
+  views::test::WidgetTest::WidgetAutoclosePtr bubble_widget(
+      views::BubbleDialogDelegateView::CreateBubble(
+          CreateDialogView(std::move(dialog_data)).release()));
+
+  auto* frame_view = static_cast<views::BubbleFrameView*>(
+      bubble_widget->non_client_view()->frame_view());
+
+  EXPECT_EQ(nullptr, frame_view->GetHeaderViewForTesting());
+}
diff --git a/chrome/browser/ui/views/tab_sharing/OWNERS b/chrome/browser/ui/views/tab_sharing/OWNERS
index eb004e66..f718b9d9 100644
--- a/chrome/browser/ui/views/tab_sharing/OWNERS
+++ b/chrome/browser/ui/views/tab_sharing/OWNERS
@@ -1,2 +1,4 @@
 marinaciocea@chromium.org
 guidou@chromium.org
+
+# COMPONENT: Blink>GetUserMedia>Desktop
diff --git a/chrome/browser/ui/views/tabs/color_picker_view.cc b/chrome/browser/ui/views/tabs/color_picker_view.cc
index 58eda37..e467326e 100644
--- a/chrome/browser/ui/views/tabs/color_picker_view.cc
+++ b/chrome/browser/ui/views/tabs/color_picker_view.cc
@@ -17,8 +17,29 @@
 #include "ui/gfx/color_utils.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/button/button.h"
+#include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/layout/box_layout.h"
-#include "ui/views/view_class_properties.h"
+
+namespace {
+
+class ColorPickerHighlightPathGenerator : public views::HighlightPathGenerator {
+ public:
+  ColorPickerHighlightPathGenerator() = default;
+
+  // views::HighlightPathGenerator:
+  SkPath GetHighlightPath(const views::View* view) override {
+    // Our highlight path should be slightly larger than the circle we paint.
+    gfx::RectF bounds(view->GetContentsBounds());
+    bounds.Inset(gfx::Insets(-2.0f));
+    const gfx::PointF center = bounds.CenterPoint();
+    return SkPath().addCircle(center.x(), center.y(), bounds.width() / 2.0f);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ColorPickerHighlightPathGenerator);
+};
+
+}  // namespace
 
 // Represents one of the colors the user can pick from. Displayed as a solid
 // circle of the given color.
@@ -38,6 +59,8 @@
     SetAccessibleName(color_name);
     SetFocusForPlatform();
     SetInstallFocusRingOnFocus(true);
+    views::HighlightPathGenerator::Install(
+        this, std::make_unique<ColorPickerHighlightPathGenerator>());
 
     SetBorder(
         views::CreateEmptyBorder(ChromeLayoutProvider::Get()->GetInsetsMetric(
@@ -89,19 +112,6 @@
 
   int GetHeightForWidth(int width) const override { return width; }
 
-  void OnBoundsChanged(const gfx::Rect& previous_bounds) override {
-    if (size() == previous_bounds.size())
-      return;
-
-    // Our highlight path should be slightly larger than the circle we paint.
-    gfx::RectF bounds(GetContentsBounds());
-    bounds.Inset(gfx::Insets(-2.0f));
-    const gfx::PointF center = bounds.CenterPoint();
-    SkPath path;
-    path.addCircle(center.x(), center.y(), bounds.width() / 2.0f);
-    SetProperty(views::kHighlightPathKey, std::move(path));
-  }
-
   void PaintButtonContents(gfx::Canvas* canvas) override {
     // Paint a colored circle surrounded by a bit of empty space.
 
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 7c649aa..bbfa77f3 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -72,6 +72,7 @@
 #include "ui/resources/grit/ui_resources.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/rect_based_targeting_utils.h"
 #include "ui/views/view.h"
@@ -114,6 +115,22 @@
   return extra_space / 2;
 }
 
+class TabStyleHighlightPathGenerator : public views::HighlightPathGenerator {
+ public:
+  explicit TabStyleHighlightPathGenerator(TabStyle* tab_style)
+      : tab_style_(tab_style) {}
+
+  // views::HighlightPathGenerator:
+  SkPath GetHighlightPath(const views::View* view) override {
+    return tab_style_->GetPath(TabStyle::PathType::kHighlight, 1.0);
+  }
+
+ private:
+  TabStyle* const tab_style_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabStyleHighlightPathGenerator);
+};
+
 }  // namespace
 
 // Helper class that observes the tab's close button.
@@ -206,6 +223,8 @@
   // Enable keyboard focus.
   SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
   focus_ring_ = views::FocusRing::Install(this);
+  views::HighlightPathGenerator::Install(
+      this, std::make_unique<TabStyleHighlightPathGenerator>(tab_style_.get()));
 }
 
 Tab::~Tab() {
@@ -400,12 +419,6 @@
   return kViewClassName;
 }
 
-void Tab::OnBoundsChanged(const gfx::Rect& previous_bounds) {
-  // Update focus ring path.
-  const SkPath path = tab_style_->GetPath(TabStyle::PathType::kHighlight, 1.0);
-  SetProperty(views::kHighlightPathKey, path);
-}
-
 bool Tab::OnKeyPressed(const ui::KeyEvent& event) {
   if (event.key_code() == ui::VKEY_SPACE && !IsSelected()) {
     controller_->SelectTab(this, event);
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index 7039e1e..f36d95b 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -79,7 +79,6 @@
   // TabSlotView:
   void Layout() override;
   const char* GetClassName() const override;
-  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
   bool OnKeyPressed(const ui::KeyEvent& event) override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
   bool OnMouseDragged(const ui::MouseEvent& event) override;
diff --git a/chrome/browser/ui/views/tabs/tab_close_button.cc b/chrome/browser/ui/views/tabs/tab_close_button.cc
index 0c99bea..b6a584d 100644
--- a/chrome/browser/ui/views/tabs/tab_close_button.cc
+++ b/chrome/browser/ui/views/tabs/tab_close_button.cc
@@ -24,9 +24,9 @@
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/animation/ink_drop.h"
 #include "ui/views/animation/ink_drop_mask.h"
+#include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/layout/layout_provider.h"
 #include "ui/views/rect_based_targeting_utils.h"
-#include "ui/views/view_class_properties.h"
 
 #if defined(USE_AURA)
 #include "ui/aura/env.h"
@@ -35,6 +35,25 @@
 namespace {
 constexpr int kGlyphWidth = 16;
 constexpr int kTouchGlyphWidth = 24;
+
+class TabCloseButtonHighlightPathGenerator
+    : public views::HighlightPathGenerator {
+ public:
+  TabCloseButtonHighlightPathGenerator() = default;
+
+  // views::HighlightPathGenerator:
+  SkPath GetHighlightPath(const views::View* view) override {
+    const gfx::Rect bounds = view->GetContentsBounds();
+    const gfx::Point center = bounds.CenterPoint();
+    const int radius = views::LayoutProvider::Get()->GetCornerRadiusMetric(
+        views::EMPHASIS_MAXIMUM, bounds.size());
+    return SkPath().addCircle(center.x(), center.y(), radius);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TabCloseButtonHighlightPathGenerator);
+};
+
 }  //  namespace
 
 TabCloseButton::TabCloseButton(views::ButtonListener* listener,
@@ -55,6 +74,8 @@
   GetInkDrop()->SetHoverHighlightFadeDuration(base::TimeDelta());
 
   SetInstallFocusRingOnFocus(true);
+  views::HighlightPathGenerator::Install(
+      this, std::make_unique<TabCloseButtonHighlightPathGenerator>());
 }
 
 TabCloseButton::~TabCloseButton() {}
@@ -120,25 +141,6 @@
   return size;
 }
 
-void TabCloseButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
-  ImageButton::OnBoundsChanged(previous_bounds);
-  auto path = std::make_unique<SkPath>();
-  const gfx::Rect bounds = GetContentsBounds();
-  const gfx::Point center = bounds.CenterPoint();
-  const int radius = views::LayoutProvider::Get()->GetCornerRadiusMetric(
-      views::EMPHASIS_MAXIMUM, bounds.size());
-  path->addCircle(center.x(), center.y(), radius);
-  SetProperty(views::kHighlightPathKey, path.release());
-}
-
-std::unique_ptr<views::InkDropMask> TabCloseButton::CreateInkDropMask() const {
-  const gfx::Rect bounds = GetContentsBounds();
-  const int radius = views::LayoutProvider::Get()->GetCornerRadiusMetric(
-      views::EMPHASIS_MAXIMUM, bounds.size());
-  return std::make_unique<views::CircleInkDropMask>(
-      size(), GetMirroredRect(bounds).CenterPoint(), radius);
-}
-
 void TabCloseButton::PaintButtonContents(gfx::Canvas* canvas) {
   cc::PaintFlags flags;
   constexpr float kStrokeWidth = 1.5f;
diff --git a/chrome/browser/ui/views/tabs/tab_close_button.h b/chrome/browser/ui/views/tabs/tab_close_button.h
index ccf1e6b..f2252abc 100644
--- a/chrome/browser/ui/views/tabs/tab_close_button.h
+++ b/chrome/browser/ui/views/tabs/tab_close_button.h
@@ -44,12 +44,10 @@
   void OnMouseReleased(const ui::MouseEvent& event) override;
   void OnMouseMoved(const ui::MouseEvent& event) override;
   void OnGestureEvent(ui::GestureEvent* event) override;
-  std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
 
  protected:
   // views::ImageButton:
   gfx::Size CalculatePreferredSize() const override;
-  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
   void PaintButtonContents(gfx::Canvas* canvas) override;
 
  private:
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
index 5d44932..676f914 100644
--- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
@@ -17,6 +17,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
 #include "chrome/browser/chromeos/login/configuration_keys.h"
@@ -103,8 +104,8 @@
   // |connector| may be null in tests.
   auto* connector = content::GetSystemConnector();
   if (connector) {
-    connector->BindInterface(ash::mojom::kServiceName,
-                             &cros_display_config_ptr_);
+    connector->Connect(ash::mojom::kServiceName,
+                       cros_display_config_.BindNewPipeAndPassReceiver());
   }
   OobeConfiguration::Get()->AddAndFireObserver(this);
 }
@@ -593,7 +594,7 @@
   const base::Value* callback_id;
   CHECK(args->Get(0, &callback_id));
 
-  cros_display_config_ptr_->GetDisplayUnitInfoList(
+  cros_display_config_->GetDisplayUnitInfoList(
       false /* single_unified */,
       base::BindOnce(&CoreOobeHandler::GetPrimaryDisplayNameCallback,
                      weak_ptr_factory_.GetWeakPtr(), callback_id->Clone()));
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h
index 2acb9fc..2785f22 100644
--- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h
@@ -23,6 +23,7 @@
 #include "chrome/browser/chromeos/login/version_info_updater.h"
 #include "chrome/browser/chromeos/tpm_firmware_update.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_webui_handler.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "ui/events/event_source.h"
 
 namespace base {
@@ -224,7 +225,7 @@
 
   DemoModeDetector demo_mode_detector_;
 
-  ash::mojom::CrosDisplayConfigControllerPtr cros_display_config_ptr_;
+  mojo::Remote<ash::mojom::CrosDisplayConfigController> cros_display_config_;
 
   base::WeakPtrFactory<CoreOobeHandler> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index 8fe6d49..29ff29e8 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -26,6 +26,7 @@
 #include "base/task/post_task.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/authpolicy/authpolicy_helper.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc b/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc
index e990f0f..d26b46a 100644
--- a/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc
+++ b/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/login/screens/network_error.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chromeos/network/network_state.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.cc b/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.cc
index 04c52902..818c8187 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.cc
@@ -45,8 +45,8 @@
   // |connector| may be null in tests.
   auto* connector = content::GetSystemConnector();
   if (connector) {
-    connector->BindInterface(ash::mojom::kServiceName,
-                             &cros_display_config_ptr_);
+    connector->Connect(ash::mojom::kServiceName,
+                       cros_display_config_.BindNewPipeAndPassReceiver());
   }
 }
 
@@ -94,7 +94,7 @@
         device.target_display_id != display::kInvalidDisplayId) {
       auto config_properties = ash::mojom::DisplayConfigProperties::New();
       config_properties->set_primary = true;
-      cros_display_config_ptr_->SetDisplayProperties(
+      cros_display_config_->SetDisplayProperties(
           base::NumberToString(device.target_display_id),
           std::move(config_properties), ash::mojom::DisplayConfigSource::kUser,
           base::DoNothing());
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.h b/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.h
index c299372..fc9cf2a9 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.h
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.h
@@ -9,6 +9,8 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/input_device_event_observer.h"
 
@@ -27,9 +29,10 @@
   // Must be called on the BrowserThread::UI thread.
   void TryToPlaceUiOnTouchDisplay();
 
-  void set_cros_display_config_ptr_for_test(
-      ash::mojom::CrosDisplayConfigControllerPtr cros_display_config_ptr) {
-    cros_display_config_ptr_ = std::move(cros_display_config_ptr);
+  void set_cros_display_config_for_test(
+      mojo::PendingRemote<ash::mojom::CrosDisplayConfigController>
+          cros_display_config) {
+    cros_display_config_.Bind(std::move(cros_display_config));
   }
 
  private:
@@ -46,7 +49,7 @@
 
   ScopedObserver<ui::DeviceDataManager, ui::InputDeviceEventObserver>
       scoped_observer_{this};
-  ash::mojom::CrosDisplayConfigControllerPtr cros_display_config_ptr_;
+  mojo::Remote<ash::mojom::CrosDisplayConfigController> cros_display_config_;
 
   base::WeakPtrFactory<OobeDisplayChooser> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser_unittest.cc b/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser_unittest.cc
index 2fd04181..407ca74 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser_unittest.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser_unittest.cc
@@ -8,11 +8,14 @@
 #include <vector>
 
 #include "ash/display/display_configuration_controller.h"
+#include "ash/public/mojom/cros_display_config.mojom.h"
 #include "ash/shell.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/test/base/chrome_ash_test_base.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/display/display.h"
 #include "ui/display/display_observer.h"
@@ -29,17 +32,17 @@
 
 class TestCrosDisplayConfig : public ash::mojom::CrosDisplayConfigController {
  public:
-  TestCrosDisplayConfig() : binding_(this) {}
+  TestCrosDisplayConfig() = default;
 
-  ash::mojom::CrosDisplayConfigControllerPtr CreateInterfacePtrAndBind() {
-    ash::mojom::CrosDisplayConfigControllerPtr ptr;
-    binding_.Bind(mojo::MakeRequest(&ptr));
-    return ptr;
+  mojo::PendingRemote<ash::mojom::CrosDisplayConfigController>
+  CreateRemoteAndBind() {
+    return receiver_.BindNewPipeAndPassRemote();
   }
 
   // ash::mojom::CrosDisplayConfigController:
-  void AddObserver(ash::mojom::CrosDisplayConfigObserverAssociatedPtrInfo
-                       observer) override {}
+  void AddObserver(
+      mojo::PendingAssociatedRemote<ash::mojom::CrosDisplayConfigObserver>
+          observer) override {}
   void GetDisplayLayoutInfo(GetDisplayLayoutInfoCallback callback) override {}
   void SetDisplayLayoutInfo(ash::mojom::DisplayLayoutInfoPtr info,
                             SetDisplayLayoutInfoCallback callback) override {}
@@ -69,7 +72,7 @@
                         TouchCalibrationCallback callback) override {}
 
  private:
-  mojo::Binding<ash::mojom::CrosDisplayConfigController> binding_;
+  mojo::Receiver<ash::mojom::CrosDisplayConfigController> receiver_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TestCrosDisplayConfig);
 };
@@ -88,8 +91,8 @@
 
     cros_display_config_ = std::make_unique<TestCrosDisplayConfig>();
     display_chooser_ = std::make_unique<OobeDisplayChooser>();
-    display_chooser_->set_cros_display_config_ptr_for_test(
-        cros_display_config_->CreateInterfacePtrAndBind());
+    display_chooser_->set_cros_display_config_for_test(
+        cros_display_config_->CreateRemoteAndBind());
 
     ui::DeviceDataManagerTestApi().OnDeviceListsComplete();
   }
diff --git a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
index 51016ebb..239071f4 100644
--- a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
+++ b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
@@ -41,6 +41,7 @@
 #include "net/cert/x509_util.h"
 #include "net/ssl/ssl_info.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
+#include "services/network/public/cpp/origin_policy.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/webui/web_ui_util.h"
 
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
index 94f7f790..711b68f 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
@@ -43,6 +43,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/printing/cups_printers_manager_factory.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/components/account_manager/account_manager.h"
diff --git a/chrome/browser/ui/webui/management_ui.cc b/chrome/browser/ui/webui/management_ui.cc
index c7aa92a..2d50de5 100644
--- a/chrome/browser/ui/webui/management_ui.cc
+++ b/chrome/browser/ui/webui/management_ui.cc
@@ -25,6 +25,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/grit/chromium_strings.h"
 #include "ui/chromeos/devicetype_utils.h"
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
index f433a77..3d53fde 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
@@ -35,6 +35,7 @@
 #include "content/public/browser/web_ui_message_handler.h"
 #include "net/log/net_log_util.h"
 #include "services/network/expect_ct_reporter.h"
+#include "services/network/public/mojom/network_context.mojom.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
index 90fc52c..bec782e 100644
--- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
@@ -15,6 +15,7 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index 936a459..1b73c3c 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -26,6 +26,7 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/printing/background_printing_manager.h"
 #include "chrome/browser/printing/print_preview_data_service.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc
index f4e49407..73502569 100644
--- a/chrome/browser/ui/webui/settings/about_handler.cc
+++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -28,6 +28,7 @@
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/obsolete_system/obsolete_system.h"
 #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc b/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc
index e2de1a9..59656e6 100644
--- a/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc
@@ -12,6 +12,7 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h"
 #include "chrome/browser/chromeos/set_time_dialog.h"
 #include "chrome/browser/chromeos/system/timezone_resolver_manager.h"
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index a3c21e1..4f98c20 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -18,6 +18,7 @@
 #include "build/buildflag.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_shortcut_manager.h"
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index dfaa529..9c9ebf7 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -83,6 +83,7 @@
 #include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
 #include "ash/public/cpp/stylus_utils.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/account_manager/account_manager_util.h"
 #include "chrome/browser/chromeos/android_sms/android_sms_app_manager.h"
 #include "chrome/browser/chromeos/android_sms/android_sms_service_factory.h"
@@ -256,6 +257,10 @@
       "a11yEnhancements",
       base::FeatureList::IsEnabled(features::kWebUIA11yEnhancements));
 
+  html_source->AddBoolean(
+      "privacySettingsRedesignEnabled",
+      base::FeatureList::IsEnabled(features::kPrivacySettingsRedesign));
+
   html_source->AddBoolean("unifiedConsentEnabled",
                           unified_consent::IsUnifiedConsentFeatureEnabled());
 
diff --git a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
index 34f1ff07..e67e546 100644
--- a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
+++ b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
@@ -76,7 +76,7 @@
 };
 
 AccountInfo GetAccountInfo(signin::IdentityManager* identity_manager,
-                           const std::string& account_id) {
+                           const CoreAccountId& account_id) {
   auto maybe_account_info =
       identity_manager
           ->FindExtendedAccountInfoForAccountWithRefreshTokenByAccountId(
@@ -141,7 +141,7 @@
     signin_metrics::AccessPoint signin_access_point,
     signin_metrics::PromoAction signin_promo_action,
     signin_metrics::Reason signin_reason,
-    const std::string& account_id,
+    const CoreAccountId& account_id,
     SigninAbortedMode signin_aborted_mode,
     std::unique_ptr<Delegate> delegate,
     base::OnceClosure callback)
@@ -204,7 +204,7 @@
     signin_metrics::AccessPoint signin_access_point,
     signin_metrics::PromoAction signin_promo_action,
     signin_metrics::Reason signin_reason,
-    const std::string& account_id,
+    const CoreAccountId& account_id,
     SigninAbortedMode signin_aborted_mode)
     : DiceTurnSyncOnHelper(
           profile,
diff --git a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h
index 20a9dfd..66f5dce0 100644
--- a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h
+++ b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h
@@ -102,7 +102,7 @@
                        signin_metrics::AccessPoint signin_access_point,
                        signin_metrics::PromoAction signin_promo_action,
                        signin_metrics::Reason signin_reason,
-                       const std::string& account_id,
+                       const CoreAccountId& account_id,
                        SigninAbortedMode signin_aborted_mode,
                        std::unique_ptr<Delegate> delegate,
                        base::OnceClosure callback);
@@ -113,7 +113,7 @@
                        signin_metrics::AccessPoint signin_access_point,
                        signin_metrics::PromoAction signin_promo_action,
                        signin_metrics::Reason signin_reason,
-                       const std::string& account_id,
+                       const CoreAccountId& account_id,
                        SigninAbortedMode signin_aborted_mode);
 
   // SyncStartupTracker::Observer:
diff --git a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_unittest.cc b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_unittest.cc
index a13b196..c1b13af 100644
--- a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_unittest.cc
+++ b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_unittest.cc
@@ -139,7 +139,7 @@
 
   void set_dm_token(const std::string& dm_token) { dm_token_ = dm_token; }
   void set_client_id(const std::string& client_id) { client_id_ = client_id; }
-  void set_account(const std::string& account_id, const std::string& email) {
+  void set_account(const CoreAccountId& account_id, const std::string& email) {
     account_id_ = account_id;
     email_ = email;
   }
@@ -147,7 +147,7 @@
   // policy::UserPolicySigninService:
   void RegisterForPolicyWithAccountId(
       const std::string& username,
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       const PolicyRegistrationCallback& callback) override {
     EXPECT_EQ(email_, username);
     EXPECT_EQ(account_id_, account_id);
@@ -167,7 +167,7 @@
  private:
   std::string dm_token_;
   std::string client_id_;
-  std::string account_id_;
+  CoreAccountId account_id_;
   std::string email_;
 };
 
@@ -236,7 +236,7 @@
   signin::IdentityManager* identity_manager() {
     return identity_test_env()->identity_manager();
   }
-  const std::string& account_id() { return account_id_; }
+  const CoreAccountId& account_id() { return account_id_; }
   FakeUserPolicySigninService* user_policy_signin_service() {
     return user_policy_signin_service_;
   }
@@ -271,7 +271,7 @@
     user_policy_signin_service_->set_account(account_id_, kEnterpriseEmail);
   }
 
-  void UseInvalidAccount() { account_id_ = "invalid_account"; }
+  void UseInvalidAccount() { account_id_ = CoreAccountId("invalid_account"); }
 
   void SetExpectationsForSyncStartupCompleted() {
     syncer::MockSyncService* mock_sync_service = GetMockSyncService();
@@ -407,7 +407,7 @@
   content::BrowserTaskEnvironment task_environment_;
   base::ScopedTempDir temp_dir_;
   ScopedTestingLocalState local_state_;
-  std::string account_id_;
+  CoreAccountId account_id_;
   std::unique_ptr<TestingProfile> profile_;
   std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
       identity_test_env_profile_adaptor_;
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
index a127593..9deb43d 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
@@ -11,6 +11,7 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/webui/signin/inline_login_handler.h"
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
index 08092d21..2b8e201ce 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
@@ -448,7 +448,7 @@
   }
 
   Browser* browser = chrome::FindLastActiveWithProfile(profile_);
-  std::string account_id =
+  CoreAccountId account_id =
       identity_manager->GetAccountsMutator()->AddOrUpdateAccount(
           gaia_id_, email_, refresh_token,
           /*is_under_advanced_protection=*/false,
diff --git a/chrome/browser/upgrade_detector/upgrade_detector_chromeos.cc b/chrome/browser/upgrade_detector/upgrade_detector_chromeos.cc
index c089e0b1..f1538ed 100644
--- a/chrome/browser/upgrade_detector/upgrade_detector_chromeos.cc
+++ b/chrome/browser/upgrade_detector/upgrade_detector_chromeos.cc
@@ -16,6 +16,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
 #include "base/rand_util.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
 #include "base/time/default_tick_clock.h"
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc
index 74afac92..c63e3ae 100644
--- a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc
+++ b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_shortcut_mac.mm b/chrome/browser/web_applications/extensions/web_app_extension_shortcut_mac.mm
index 9f8a0e6..032b3c3 100644
--- a/chrome/browser/web_applications/extensions/web_app_extension_shortcut_mac.mm
+++ b/chrome/browser/web_applications/extensions/web_app_extension_shortcut_mac.mm
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/command_line.h"
 #include "base/task/post_task.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 362171b..321ff9e 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -596,6 +596,11 @@
 const base::Feature kPrerenderFallbackToPreconnect{
     "PrerenderFallbackToPreconnect", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Whether to display redesign of the chrome privacy settings page
+// to the user.
+const base::Feature kPrivacySettingsRedesign{"PrivacySettingsRedesign",
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
+
 #if BUILDFLAG(ENABLE_PLUGINS)
 // Show Flash deprecation warning to users who have manually enabled Flash.
 // https://crbug.com/918428
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index a305be4..c7d9c731 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -375,6 +375,9 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kPrerenderFallbackToPreconnect;
 
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kPrivacySettingsRedesign;
+
 #if BUILDFLAG(ENABLE_PLUGINS)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kFlashDeprecationWarning;
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 6c83a061..a43cae8 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -2480,6 +2480,22 @@
 }
 
 // static
+base::FilePath ShellUtil::GetApplicationPathForProgId(
+    const base::string16& prog_id) {
+  base::string16 prog_id_path(kRegClasses);
+  prog_id_path.push_back(base::FilePath::kSeparators[0]);
+  prog_id_path.append(prog_id);
+  prog_id_path.append(kRegShellOpen);
+  base::string16 command_line;
+  RegKey command_line_key(HKEY_CURRENT_USER, prog_id_path.c_str(),
+                          KEY_QUERY_VALUE);
+  if (command_line_key.ReadValue(L"", &command_line) == ERROR_SUCCESS)
+    return base::CommandLine::FromString(command_line).GetProgram();
+
+  return base::FilePath();
+}
+
+// static
 bool ShellUtil::AddRegistryEntries(
     HKEY root,
     const std::vector<std::unique_ptr<RegistryEntry>>& entries) {
diff --git a/chrome/installer/util/shell_util.h b/chrome/installer/util/shell_util.h
index 6ba6b75..77b72d5 100644
--- a/chrome/installer/util/shell_util.h
+++ b/chrome/installer/util/shell_util.h
@@ -651,6 +651,14 @@
   // with this name will be deleted.
   static bool DeleteFileAssociations(const base::string16& prog_id);
 
+  // Retrieves the file path of the application registered as the
+  // shell->open->command for |prog_id|. This only queries the user's
+  // registered applications in HKCU. If |prog_id| is for an app that is
+  // unrelated to the user's browser, it will still return the application
+  // registered for |prog_id|.
+  static base::FilePath GetApplicationPathForProgId(
+      const base::string16& prog_id);
+
   // This method converts all the RegistryEntries from the given list to
   // Set/CreateRegWorkItems and runs them using WorkItemList.
   static bool AddRegistryEntries(
diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc
index 83c60ed..e582aab58 100644
--- a/chrome/installer/util/shell_util_unittest.cc
+++ b/chrome/installer/util/shell_util_unittest.cc
@@ -903,7 +903,7 @@
 
 TEST_F(ShellUtilRegistryTest, DeleteFileAssociations) {
   // Create file associations.
-  EXPECT_TRUE(ShellUtil::AddFileAssociations(
+  ASSERT_TRUE(ShellUtil::AddFileAssociations(
       kTestProgid, OpenCommand(), kTestApplicationName, kTestFileTypeName,
       base::FilePath(kTestIconPath), FileExtensions()));
 
@@ -940,6 +940,15 @@
   EXPECT_EQ(L"SomeOtherApp", value);
 }
 
+TEST_F(ShellUtilRegistryTest, GetApplicationForProgId) {
+  // Create file associations.
+  ASSERT_TRUE(ShellUtil::AddFileAssociations(
+      kTestProgid, OpenCommand(), kTestApplicationName, kTestFileTypeName,
+      base::FilePath(kTestIconPath), FileExtensions()));
+  base::FilePath exe_path = ShellUtil::GetApplicationPathForProgId(kTestProgid);
+  EXPECT_EQ(exe_path, base::FilePath(kTestOpenCommand));
+}
+
 TEST(ShellUtilTest, BuildAppModelIdBasic) {
   std::vector<base::string16> components;
   const base::string16 base_app_id(install_static::GetBaseAppId());
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
index 765981f..ec3466f2 100644
--- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -1718,6 +1718,8 @@
   EXPECT_TRUE(
       password_autofill_agent_->TryToShowTouchToFill(username_element_));
   EXPECT_TRUE(password_autofill_agent_->ShouldSuppressKeyboard());
+  EXPECT_EQ(WebAutofillState::kPreviewed, username_element_.GetAutofillState());
+  EXPECT_EQ(WebAutofillState::kPreviewed, password_element_.GetAutofillState());
 
   EXPECT_CALL(fake_driver_, ShowTouchToFill);
   base::RunLoop().RunUntilIdle();
@@ -1729,6 +1731,7 @@
   EXPECT_TRUE(
       password_autofill_agent_->TryToShowTouchToFill(password_element_));
   EXPECT_TRUE(password_autofill_agent_->ShouldSuppressKeyboard());
+  EXPECT_EQ(WebAutofillState::kPreviewed, password_element_.GetAutofillState());
 
   EXPECT_CALL(fake_driver_, ShowTouchToFill);
   base::RunLoop().RunUntilIdle();
@@ -1745,19 +1748,23 @@
 TEST_F(PasswordAutofillAgentTest, TouchToFillDismissed) {
   SimulateOnFillPasswordForm(fill_data_);
 
+  auto previous_state = password_element_.GetAutofillState();
   // Touch to fill will be shown multiple times until TouchToFillDismissed()
   // gets called.
   EXPECT_TRUE(
       password_autofill_agent_->TryToShowTouchToFill(password_element_));
   EXPECT_TRUE(password_autofill_agent_->ShouldSuppressKeyboard());
+  EXPECT_EQ(WebAutofillState::kPreviewed, password_element_.GetAutofillState());
 
   EXPECT_CALL(fake_driver_, ShowTouchToFill);
   base::RunLoop().RunUntilIdle();
 
+  // Make sure that resetting Touch To Fill resets the Autofill state.
   password_autofill_agent_->TouchToFillDismissed();
   EXPECT_FALSE(
       password_autofill_agent_->TryToShowTouchToFill(password_element_));
   EXPECT_FALSE(password_autofill_agent_->ShouldSuppressKeyboard());
+  EXPECT_EQ(previous_state, password_element_.GetAutofillState());
 
   // Reload the page and simulate fill.
   LoadHTML(kFormHTML);
@@ -1769,6 +1776,7 @@
   EXPECT_TRUE(
       password_autofill_agent_->TryToShowTouchToFill(password_element_));
   EXPECT_TRUE(password_autofill_agent_->ShouldSuppressKeyboard());
+  EXPECT_EQ(WebAutofillState::kPreviewed, password_element_.GetAutofillState());
 
   EXPECT_CALL(fake_driver_, ShowTouchToFill);
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/services/app_service/app_service_impl.cc b/chrome/services/app_service/app_service_impl.cc
index 29cf66bc..4d89fc7 100644
--- a/chrome/services/app_service/app_service_impl.cc
+++ b/chrome/services/app_service/app_service_impl.cc
@@ -126,13 +126,24 @@
   iter->second->SetPermission(app_id, std::move(permission));
 }
 
-void AppServiceImpl::Uninstall(apps::mojom::AppType app_type,
-                               const std::string& app_id) {
+void AppServiceImpl::PromptUninstall(apps::mojom::AppType app_type,
+                                     const std::string& app_id) {
   auto iter = publishers_.find(app_type);
   if (iter == publishers_.end()) {
     return;
   }
-  iter->second->Uninstall(app_id);
+  iter->second->PromptUninstall(app_id);
+}
+
+void AppServiceImpl::Uninstall(apps::mojom::AppType app_type,
+                               const std::string& app_id,
+                               bool clear_site_data,
+                               bool report_abuse) {
+  auto iter = publishers_.find(app_type);
+  if (iter == publishers_.end()) {
+    return;
+  }
+  iter->second->Uninstall(app_id, clear_site_data, report_abuse);
 }
 
 void AppServiceImpl::OpenNativeSettings(apps::mojom::AppType app_type,
diff --git a/chrome/services/app_service/app_service_impl.h b/chrome/services/app_service/app_service_impl.h
index 7e7cf370..ebb4509 100644
--- a/chrome/services/app_service/app_service_impl.h
+++ b/chrome/services/app_service/app_service_impl.h
@@ -56,8 +56,12 @@
   void SetPermission(apps::mojom::AppType app_type,
                      const std::string& app_id,
                      apps::mojom::PermissionPtr permission) override;
+  void PromptUninstall(apps::mojom::AppType app_type,
+                       const std::string& app_id) override;
   void Uninstall(apps::mojom::AppType app_type,
-                 const std::string& app_id) override;
+                 const std::string& app_id,
+                 bool clear_site_data,
+                 bool report_abuse) override;
   void OpenNativeSettings(apps::mojom::AppType app_type,
                           const std::string& app_id) override;
 
diff --git a/chrome/services/app_service/app_service_impl_unittest.cc b/chrome/services/app_service/app_service_impl_unittest.cc
index 252f6a0..448f2766 100644
--- a/chrome/services/app_service/app_service_impl_unittest.cc
+++ b/chrome/services/app_service/app_service_impl_unittest.cc
@@ -76,7 +76,10 @@
   void SetPermission(const std::string& app_id,
                      apps::mojom::PermissionPtr permission) override {}
 
-  void Uninstall(const std::string& app_id) override {}
+  void PromptUninstall(const std::string& app_id) override {}
+  void Uninstall(const std::string& app_id,
+                 bool clear_site_data,
+                 bool report_abuse) override {}
 
   void OpenNativeSettings(const std::string& app_id) override {}
 
diff --git a/chrome/services/app_service/public/mojom/app_service.mojom b/chrome/services/app_service/public/mojom/app_service.mojom
index 19def9e..42d9e955 100644
--- a/chrome/services/app_service/public/mojom/app_service.mojom
+++ b/chrome/services/app_service/public/mojom/app_service.mojom
@@ -53,10 +53,23 @@
       string app_id,
       Permission permission);
 
-  Uninstall(
+  // Uninstall which invokes a specific dialog per app type. When the unified
+  // uninstall dialog is done, this interface will be removed.
+  PromptUninstall(
       AppType app_type,
       string app_id);
 
+  // Directly uninstalls |app_id| without prompting the user.
+  // |clear_site_data| is available for bookmark apps only. If true, any site
+  // data associated with the app will be removed..
+  // |report_abuse| is available for Chrome Apps only. If true, the app will be
+  // reported for abuse to the Web Store.
+  Uninstall(
+      AppType app_type,
+      string app_id,
+      bool clear_site_data,
+      bool report_abuse);
+
   OpenNativeSettings(
       AppType app_type,
       string app_id);
@@ -93,9 +106,21 @@
       string app_id,
       Permission permission);
 
-  Uninstall(
+  // Uninstall which invokes a specific dialog per app type. When the unified
+  // uninstall dialog is done, this interface will be removed.
+  PromptUninstall(
       string app_id);
 
+  // Directly uninstalls |app_id| without prompting the user.
+  // |clear_site_data| is available for bookmark apps only. If true, any site
+  // data associated with the app will be removed..
+  // |report_abuse| is available for Chrome Apps only. If true, the app will be
+  // reported for abuse to the Web Store.
+  Uninstall(
+      string app_id,
+      bool clear_site_data,
+      bool report_abuse);
+
   OpenNativeSettings(
       string app_id);
 };
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 06b05c5..d2b1e6c 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -29,6 +29,7 @@
 #include "chrome/browser/bookmarks/chrome_bookmark_client.h"
 #include "chrome/browser/bookmarks/managed_bookmark_service_factory.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_factory.h"
 #include "chrome/browser/chrome_content_browser_client.h"
diff --git a/chrome/test/data/password/captured_sites/testcases.json b/chrome/test/data/password/captured_sites/testcases.json
index 62ab60d1..42d6ce5 100644
--- a/chrome/test/data/password/captured_sites/testcases.json
+++ b/chrome/test/data/password/captured_sites/testcases.json
@@ -17,7 +17,7 @@
     { "scenario_dir":"capture_update_pass", "site_name":"rakuten" },
     { "scenario_dir":"capture_update_pass", "site_name":"readtheory" },
     { "scenario_dir":"capture_update_pass", "site_name":"roblox" },
-    { "scenario_dir":"capture_update_pass", "site_name":"southwest" },
+    { "scenario_dir":"capture_update_pass", "site_name":"southwest", "disabled":true, "bug_number":1014333 },
     { "scenario_dir":"capture_update_pass", "site_name":"steam" },
     { "scenario_dir":"capture_update_pass", "site_name":"the_sims_resource" },
     { "scenario_dir":"capture_update_pass", "site_name":"united" },
diff --git a/chrome/test/data/webrtc/peerconnection_getstats.js b/chrome/test/data/webrtc/peerconnection_getstats.js
index d5506fa..129d730 100644
--- a/chrome/test/data/webrtc/peerconnection_getstats.js
+++ b/chrome/test/data/webrtc/peerconnection_getstats.js
@@ -124,6 +124,7 @@
   fecPacketsReceived: 'number',
   fecPacketsDiscarded: 'number',
   bytesReceived: 'number',
+  headerBytesReceived: 'number',
   packetsFailedDecryption: 'number',
   packetsDuplicated: 'number',
   perDscpPacketsReceived: 'object',
@@ -180,6 +181,7 @@
   lastPacketSentTimestamp: 'number',
   retransmittedPacketsSent: 'number',
   retransmittedBytesSent: 'number',
+  headerBytesSent: 'number',
   targetBitrate: 'number',
   totalEncodedBytesTarget: 'number',
   framesEncoded: 'number',
diff --git a/chromecast/browser/cast_network_contexts.cc b/chromecast/browser/cast_network_contexts.cc
index 46b316c..633697e 100644
--- a/chromecast/browser/cast_network_contexts.cc
+++ b/chromecast/browser/cast_network_contexts.cc
@@ -24,6 +24,7 @@
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/storage_partition.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "services/network/network_context.h"
 #include "services/network/public/cpp/cross_thread_shared_url_loader_factory_info.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -244,10 +245,10 @@
     proxy_config_service_->AddObserver(this);
   }
 
-  network::mojom::ProxyConfigClientPtr proxy_config_client;
-  network_context_params->proxy_config_client_request =
-      mojo::MakeRequest(&proxy_config_client);
-  proxy_config_client_set_.AddPtr(std::move(proxy_config_client));
+  mojo::PendingRemote<network::mojom::ProxyConfigClient> proxy_config_client;
+  network_context_params->proxy_config_client_receiver =
+      proxy_config_client.InitWithNewPipeAndPassReceiver();
+  proxy_config_client_set_.Add(std::move(proxy_config_client));
 
   poller_binding_set_.AddBinding(
       this,
@@ -264,22 +265,20 @@
     const net::ProxyConfigWithAnnotation& config,
     net::ProxyConfigService::ConfigAvailability availability) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  proxy_config_client_set_.ForAllPtrs(
-      [config,
-       availability](network::mojom::ProxyConfigClient* proxy_config_client) {
-        switch (availability) {
-          case net::ProxyConfigService::CONFIG_VALID:
-            proxy_config_client->OnProxyConfigUpdated(config);
-            break;
-          case net::ProxyConfigService::CONFIG_UNSET:
-            proxy_config_client->OnProxyConfigUpdated(
-                net::ProxyConfigWithAnnotation::CreateDirect());
-            break;
-          case net::ProxyConfigService::CONFIG_PENDING:
-            NOTREACHED();
-            break;
-        }
-      });
+  for (const auto& proxy_config_client : proxy_config_client_set_) {
+    switch (availability) {
+      case net::ProxyConfigService::CONFIG_VALID:
+        proxy_config_client->OnProxyConfigUpdated(config);
+        break;
+      case net::ProxyConfigService::CONFIG_UNSET:
+        proxy_config_client->OnProxyConfigUpdated(
+            net::ProxyConfigWithAnnotation::CreateDirect());
+        break;
+      case net::ProxyConfigService::CONFIG_PENDING:
+        NOTREACHED();
+        break;
+    }
+  }
 }
 
 void CastNetworkContexts::OnLazyProxyConfigPoll() {
diff --git a/chromecast/browser/cast_network_contexts.h b/chromecast/browser/cast_network_contexts.h
index 4cf050f..89498402 100644
--- a/chromecast/browser/cast_network_contexts.h
+++ b/chromecast/browser/cast_network_contexts.h
@@ -12,8 +12,8 @@
 #include "base/memory/scoped_refptr.h"
 #include "content/public/browser/browser_thread.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
 #include "net/proxy_resolution/proxy_config_service.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 #include "services/network/public/mojom/proxy_config.mojom.h"
@@ -123,8 +123,7 @@
   std::unique_ptr<PrefProxyConfigTracker> pref_proxy_config_tracker_impl_;
 
   mojo::BindingSet<network::mojom::ProxyConfigPollerClient> poller_binding_set_;
-  mojo::InterfacePtrSet<network::mojom::ProxyConfigClient>
-      proxy_config_client_set_;
+  mojo::RemoteSet<network::mojom::ProxyConfigClient> proxy_config_client_set_;
 
   DISALLOW_COPY_AND_ASSIGN(CastNetworkContexts);
 };
diff --git a/chromeos/components/drivefs/drivefs_bootstrap.cc b/chromeos/components/drivefs/drivefs_bootstrap.cc
index a2b1fab3..9404a18d 100644
--- a/chromeos/components/drivefs/drivefs_bootstrap.cc
+++ b/chromeos/components/drivefs/drivefs_bootstrap.cc
@@ -7,16 +7,18 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
 #include "chromeos/components/drivefs/pending_connection_manager.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/platform/platform_channel_endpoint.h"
 #include "mojo/public/cpp/system/invitation.h"
 
 namespace drivefs {
 
 DriveFsBootstrapListener::DriveFsBootstrapListener()
-    : bootstrap_(mojo::MakeProxy(mojom::DriveFsBootstrapPtrInfo(
-          invitation_.AttachMessagePipe("drivefs-bootstrap"),
-          mojom::DriveFsBootstrap::Version_))),
+    : bootstrap_(invitation_.AttachMessagePipe("drivefs-bootstrap"),
+                 mojom::DriveFsBootstrap::Version_),
       pending_token_(base::UnguessableToken::Create()) {
   PendingConnectionManager::Get().ExpectOpenIpcChannel(
       pending_token_,
@@ -32,7 +34,8 @@
   }
 }
 
-mojom::DriveFsBootstrapPtr DriveFsBootstrapListener::bootstrap() {
+mojo::PendingRemote<mojom::DriveFsBootstrap>
+DriveFsBootstrapListener::bootstrap() {
   return std::move(bootstrap_);
 }
 
@@ -61,22 +64,20 @@
 
   base::UnguessableToken Connect(mojom::DriveFsDelegate* delegate,
                                  base::OnceClosure on_disconnected) override {
-    delegate_binding_ =
-        std::make_unique<mojo::Binding<mojom::DriveFsDelegate>>(delegate);
+    delegate_receiver_ =
+        std::make_unique<mojo::Receiver<mojom::DriveFsDelegate>>(delegate);
     on_disconnected_ = std::move(on_disconnected);
 
-    auto bootstrap = bootstrap_listener_->bootstrap();
+    auto bootstrap =
+        mojo::Remote<mojom::DriveFsBootstrap>(bootstrap_listener_->bootstrap());
     auto token = bootstrap_listener_->pending_token();
 
-    mojom::DriveFsDelegatePtr delegate_ptr;
-    delegate_binding_->Bind(mojo::MakeRequest(&delegate_ptr));
-    delegate_binding_->set_connection_error_handler(base::BindOnce(
+    bootstrap->Init(std::move(config_), drivefs_.BindNewPipeAndPassReceiver(),
+                    delegate_receiver_->BindNewPipeAndPassRemote());
+
+    delegate_receiver_->set_disconnect_handler(base::BindOnce(
         &DriveFsConnectionImpl::OnMojoConnectionError, base::Unretained(this)));
-
-    bootstrap->Init(std::move(config_), mojo::MakeRequest(&drivefs_),
-                    std::move(delegate_ptr));
-
-    drivefs_.set_connection_error_handler(base::BindOnce(
+    drivefs_.set_disconnect_handler(base::BindOnce(
         &DriveFsConnectionImpl::OnMojoConnectionError, base::Unretained(this)));
 
     return token;
@@ -97,8 +98,8 @@
   const std::unique_ptr<DriveFsBootstrapListener> bootstrap_listener_;
   mojom::DriveFsConfigurationPtr config_;
 
-  std::unique_ptr<mojo::Binding<mojom::DriveFsDelegate>> delegate_binding_;
-  mojom::DriveFsPtr drivefs_;
+  std::unique_ptr<mojo::Receiver<mojom::DriveFsDelegate>> delegate_receiver_;
+  mojo::Remote<mojom::DriveFs> drivefs_;
 
   base::OnceClosure on_disconnected_;
 
diff --git a/chromeos/components/drivefs/drivefs_bootstrap.h b/chromeos/components/drivefs/drivefs_bootstrap.h
index 6673390e..17d4b44 100644
--- a/chromeos/components/drivefs/drivefs_bootstrap.h
+++ b/chromeos/components/drivefs/drivefs_bootstrap.h
@@ -12,7 +12,7 @@
 #include "base/macros.h"
 #include "base/unguessable_token.h"
 #include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/system/invitation.h"
 
 namespace drivefs {
@@ -24,7 +24,7 @@
   virtual ~DriveFsBootstrapListener();
 
   const base::UnguessableToken& pending_token() const { return pending_token_; }
-  virtual mojom::DriveFsBootstrapPtr bootstrap();
+  virtual mojo::PendingRemote<mojom::DriveFsBootstrap> bootstrap();
   bool is_connected() const { return connected_; }
 
  protected:
@@ -35,7 +35,7 @@
   void AcceptMojoConnection(base::ScopedFD handle);
 
   mojo::OutgoingInvitation invitation_;
-  mojom::DriveFsBootstrapPtr bootstrap_;
+  mojo::PendingRemote<mojom::DriveFsBootstrap> bootstrap_;
 
   // The token passed to DriveFS as part of 'source path' used to match it to
   // this instance.
diff --git a/chromeos/components/drivefs/drivefs_bootstrap_unittest.cc b/chromeos/components/drivefs/drivefs_bootstrap_unittest.cc
index ae8daaa..d15d276 100644
--- a/chromeos/components/drivefs/drivefs_bootstrap_unittest.cc
+++ b/chromeos/components/drivefs/drivefs_bootstrap_unittest.cc
@@ -5,12 +5,18 @@
 #include "chromeos/components/drivefs/drivefs_bootstrap.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
 #include "chromeos/components/drivefs/mojom/drivefs.mojom-test-utils.h"
+#include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
 #include "chromeos/components/drivefs/pending_connection_manager.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -38,17 +44,17 @@
 class DriveFsBootstrapListenerForTest : public DriveFsBootstrapListener {
  public:
   DriveFsBootstrapListenerForTest(
-      mojom::DriveFsBootstrapPtrInfo available_bootstrap)
+      mojo::PendingRemote<mojom::DriveFsBootstrap> available_bootstrap)
       : available_bootstrap_(std::move(available_bootstrap)) {}
 
-  mojom::DriveFsBootstrapPtr bootstrap() override {
-    return mojo::MakeProxy(std::move(available_bootstrap_));
+  mojo::PendingRemote<mojom::DriveFsBootstrap> bootstrap() override {
+    return std::move(available_bootstrap_);
   }
 
   void SendInvitationOverPipe(base::ScopedFD) override {}
 
  private:
-  mojom::DriveFsBootstrapPtrInfo available_bootstrap_;
+  mojo::PendingRemote<mojom::DriveFsBootstrap> available_bootstrap_;
 
   DISALLOW_COPY_AND_ASSIGN(DriveFsBootstrapListenerForTest);
 };
@@ -56,27 +62,24 @@
 class DriveFsBootstrapTest : public testing::Test,
                              public mojom::DriveFsBootstrap {
  public:
-  DriveFsBootstrapTest() : bootstrap_binding_(this), binding_(&mock_drivefs_) {}
+  DriveFsBootstrapTest() = default;
 
  protected:
   MOCK_CONST_METHOD0(OnDisconnect, void());
   MOCK_CONST_METHOD0(OnInit, void());
 
   void Init(mojom::DriveFsConfigurationPtr config,
-            mojom::DriveFsRequest drive_fs_request,
-            mojom::DriveFsDelegatePtr delegate) override {
-    binding_.Bind(std::move(drive_fs_request));
-    mojo::FuseInterface(std::move(pending_delegate_request_),
-                        delegate.PassInterface());
+            mojo::PendingReceiver<mojom::DriveFs> drive_fs_receiver,
+            mojo::PendingRemote<mojom::DriveFsDelegate> delegate) override {
+    receiver_.Bind(std::move(drive_fs_receiver));
+    mojo::FusePipes(std::move(pending_delegate_receiver_), std::move(delegate));
     OnInit();
   }
 
   std::unique_ptr<DriveFsBootstrapListener> CreateListener() {
-    mojom::DriveFsBootstrapPtrInfo pending_bootstrap;
-    bootstrap_binding_.Bind(mojo::MakeRequest(&pending_bootstrap));
-    pending_delegate_request_ = mojo::MakeRequest(&delegate_ptr_);
+    pending_delegate_receiver_ = delegate_.BindNewPipeAndPassReceiver();
     return std::make_unique<DriveFsBootstrapListenerForTest>(
-        std::move(pending_bootstrap));
+        bootstrap_receiver_.BindNewPipeAndPassRemote());
   }
 
   base::UnguessableToken ListenForConnection() {
@@ -91,7 +94,7 @@
     ASSERT_TRUE(
         PendingConnectionManager::Get().OpenIpcChannel(token.ToString(), {}));
     base::RunLoop run_loop;
-    bootstrap_binding_.set_connection_error_handler(run_loop.QuitClosure());
+    bootstrap_receiver_.set_disconnect_handler(run_loop.QuitClosure());
     run_loop.Run();
   }
 
@@ -99,11 +102,11 @@
   MockDriveFs mock_drivefs_;
   MockDriveFsDelegate mock_delegate_;
 
-  mojo::Binding<mojom::DriveFsBootstrap> bootstrap_binding_;
-  mojo::Binding<mojom::DriveFs> binding_;
+  mojo::Receiver<mojom::DriveFsBootstrap> bootstrap_receiver_{this};
+  mojo::Receiver<mojom::DriveFs> receiver_{&mock_drivefs_};
   std::unique_ptr<DriveFsConnection> connection_;
-  mojom::DriveFsDelegatePtr delegate_ptr_;
-  mojom::DriveFsDelegateRequest pending_delegate_request_;
+  mojo::Remote<mojom::DriveFsDelegate> delegate_;
+  mojo::PendingReceiver<mojom::DriveFsDelegate> pending_delegate_receiver_;
   std::string email_;
 
   DISALLOW_COPY_AND_ASSIGN(DriveFsBootstrapTest);
@@ -116,7 +119,7 @@
   EXPECT_CALL(*this, OnInit());
   WaitForConnection(token);
   EXPECT_CALL(*this, OnDisconnect());
-  binding_.Close();
+  receiver_.reset();
   base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(
       PendingConnectionManager::Get().OpenIpcChannel(token.ToString(), {}));
@@ -127,7 +130,7 @@
   EXPECT_CALL(*this, OnInit());
   WaitForConnection(token);
   EXPECT_CALL(*this, OnDisconnect());
-  delegate_ptr_.reset();
+  delegate_.reset();
   base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(
       PendingConnectionManager::Get().OpenIpcChannel(token.ToString(), {}));
@@ -156,7 +159,7 @@
 TEST_F(DriveFsBootstrapTest, Listen_DisconnectDelegate) {
   EXPECT_CALL(*this, OnDisconnect()).Times(0);
   ListenForConnection();
-  delegate_ptr_.reset();
+  delegate_.reset();
   base::RunLoop().RunUntilIdle();
 }
 
diff --git a/chromeos/components/drivefs/drivefs_host_unittest.cc b/chromeos/components/drivefs/drivefs_host_unittest.cc
index 4c6dde2..452c74e5 100644
--- a/chromeos/components/drivefs/drivefs_host_unittest.cc
+++ b/chromeos/components/drivefs/drivefs_host_unittest.cc
@@ -21,13 +21,18 @@
 #include "chromeos/components/drivefs/drivefs_host_observer.h"
 #include "chromeos/components/drivefs/fake_drivefs.h"
 #include "chromeos/components/drivefs/mojom/drivefs.mojom-test-utils.h"
+#include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
 #include "chromeos/components/drivefs/pending_connection_manager.h"
 #include "chromeos/disks/mock_disk_mount_manager.h"
 #include "components/drive/drive_notification_manager.h"
 #include "components/drive/drive_notification_observer.h"
 #include "components/invalidation/impl/fake_invalidation_service.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/clone_traits.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/identity/public/mojom/identity_accessor.mojom-test-utils.h"
 #include "services/identity/public/mojom/identity_service.mojom.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -43,7 +48,7 @@
 class MockDriveFs : public mojom::DriveFsInterceptorForTesting,
                     public mojom::SearchQuery {
  public:
-  MockDriveFs() : search_binding_(this) {}
+  MockDriveFs() = default;
 
   DriveFs* GetForwardingInterface() override {
     NOTREACHED();
@@ -65,12 +70,11 @@
   MOCK_METHOD0(FetchAllChangeLogs, void());
 
   MOCK_CONST_METHOD1(OnStartSearchQuery, void(const mojom::QueryParameters&));
-  void StartSearchQuery(mojom::SearchQueryRequest query,
+  void StartSearchQuery(mojo::PendingReceiver<mojom::SearchQuery> receiver,
                         mojom::QueryParametersPtr query_params) override {
-    if (search_binding_.is_bound())
-      search_binding_.Unbind();
+    search_receiver_.reset();
     OnStartSearchQuery(*query_params);
-    search_binding_.Bind(std::move(query));
+    search_receiver_.Bind(std::move(receiver));
   }
 
   MOCK_METHOD1(OnGetNextPage,
@@ -84,7 +88,7 @@
   }
 
  private:
-  mojo::Binding<mojom::SearchQuery> search_binding_;
+  mojo::Receiver<mojom::SearchQuery> search_receiver_{this};
 };
 
 class TestingDriveFsHostDelegate : public DriveFsHost::Delegate,
@@ -100,7 +104,8 @@
     drive_notification_manager_.Shutdown();
   }
 
-  void set_pending_bootstrap(mojom::DriveFsBootstrapPtrInfo pending_bootstrap) {
+  void set_pending_bootstrap(
+      mojo::PendingRemote<mojom::DriveFsBootstrap> pending_bootstrap) {
     pending_bootstrap_ = std::move(pending_bootstrap);
   }
 
@@ -147,7 +152,7 @@
 
   identity::mojom::IdentityService* const identity_service_;
   const AccountId account_id_;
-  mojom::DriveFsBootstrapPtrInfo pending_bootstrap_;
+  mojo::PendingRemote<mojom::DriveFsBootstrap> pending_bootstrap_;
   invalidation::FakeInvalidationService invalidation_service_;
   drive::DriveNotificationManager drive_notification_manager_;
 
@@ -257,9 +262,7 @@
   DriveFsHostTest()
       : network_connection_tracker_(
             network::TestNetworkConnectionTracker::CreateInstance()),
-        mock_identity_accessor_(&clock_),
-        bootstrap_binding_(this),
-        binding_(&mock_drivefs_) {
+        mock_identity_accessor_(&clock_) {
     clock_.SetNow(base::Time::Now());
   }
 
@@ -306,10 +309,9 @@
             _, chromeos::MOUNT_ACCESS_MODE_READ_WRITE))
         .WillOnce(testing::SaveArg<0>(&source));
 
-    mojom::DriveFsBootstrapPtrInfo bootstrap;
-    bootstrap_binding_.Bind(mojo::MakeRequest(&bootstrap));
-    host_delegate_->set_pending_bootstrap(std::move(bootstrap));
-    pending_delegate_request_ = mojo::MakeRequest(&delegate_ptr_);
+    host_delegate_->set_pending_bootstrap(
+        bootstrap_receiver_.BindNewPipeAndPassRemote());
+    pending_delegate_receiver_ = delegate_.BindNewPipeAndPassReceiver();
 
     EXPECT_TRUE(host_->Mount());
     testing::Mock::VerifyAndClear(&disk_manager_);
@@ -326,14 +328,14 @@
                         {}});
   }
 
-  void SendOnMounted() { delegate_ptr_->OnMounted(); }
+  void SendOnMounted() { delegate_->OnMounted(); }
 
   void SendOnUnmounted(base::Optional<base::TimeDelta> delay) {
-    delegate_ptr_->OnUnmounted(std::move(delay));
+    delegate_->OnUnmounted(std::move(delay));
   }
 
   void SendMountFailed(base::Optional<base::TimeDelta> delay) {
-    delegate_ptr_->OnMountFailed(std::move(delay));
+    delegate_->OnMountFailed(std::move(delay));
   }
 
   void EstablishConnection() {
@@ -343,7 +345,7 @@
     ASSERT_TRUE(PendingConnectionManager::Get().OpenIpcChannel(token_, {}));
     {
       base::RunLoop run_loop;
-      bootstrap_binding_.set_connection_error_handler(run_loop.QuitClosure());
+      bootstrap_receiver_.set_disconnect_handler(run_loop.QuitClosure());
       run_loop.Run();
     }
   }
@@ -366,9 +368,9 @@
   void DoUnmount() {
     EXPECT_CALL(*host_delegate_, OnUnmounted(_)).Times(0);
     host_->Unmount();
-    binding_.Unbind();
-    bootstrap_binding_.Unbind();
-    delegate_ptr_.reset();
+    receiver_.reset();
+    bootstrap_receiver_.reset();
+    delegate_.reset();
     base::RunLoop().RunUntilIdle();
     testing::Mock::VerifyAndClearExpectations(disk_manager_.get());
     testing::Mock::VerifyAndClearExpectations(host_delegate_.get());
@@ -378,7 +380,7 @@
                          const std::string& expected_token) {
     base::RunLoop run_loop;
     auto quit_closure = run_loop.QuitClosure();
-    delegate_ptr_->GetAccessToken(
+    delegate_->GetAccessToken(
         "client ID", "app ID", {"scope1", "scope2"},
         base::BindLambdaForTesting(
             [&](mojom::AccessTokenStatus status, const std::string& token) {
@@ -390,15 +392,14 @@
   }
 
   void Init(mojom::DriveFsConfigurationPtr config,
-            mojom::DriveFsRequest drive_fs_request,
-            mojom::DriveFsDelegatePtr delegate) override {
+            mojo::PendingReceiver<mojom::DriveFs> drive_fs_receiver,
+            mojo::PendingRemote<mojom::DriveFsDelegate> delegate) override {
     EXPECT_EQ("test@example.com", config->user_email);
     EXPECT_EQ("recovered files",
               config->lost_and_found_directory_name.value_or("<None>"));
     init_access_token_ = std::move(config->access_token);
-    binding_.Bind(std::move(drive_fs_request));
-    mojo::FuseInterface(std::move(pending_delegate_request_),
-                        delegate.PassInterface());
+    receiver_.Bind(std::move(drive_fs_receiver));
+    mojo::FusePipes(std::move(pending_delegate_receiver_), std::move(delegate));
   }
 
   base::FilePath profile_path_;
@@ -414,11 +415,11 @@
   std::unique_ptr<DriveFsHost> host_;
   base::MockOneShotTimer* timer_;
 
-  mojo::Binding<mojom::DriveFsBootstrap> bootstrap_binding_;
+  mojo::Receiver<mojom::DriveFsBootstrap> bootstrap_receiver_{this};
   MockDriveFs mock_drivefs_;
-  mojo::Binding<mojom::DriveFs> binding_;
-  mojom::DriveFsDelegatePtr delegate_ptr_;
-  mojom::DriveFsDelegateRequest pending_delegate_request_;
+  mojo::Receiver<mojom::DriveFs> receiver_{&mock_drivefs_};
+  mojo::Remote<mojom::DriveFsDelegate> delegate_;
+  mojo::PendingReceiver<mojom::DriveFsDelegate> pending_delegate_receiver_;
   std::string token_;
   base::Optional<std::string> init_access_token_;
 
@@ -445,7 +446,7 @@
   EXPECT_CALL(observer, OnUnmounted());
   EXPECT_CALL(*host_delegate_, OnUnmounted(_)).Times(0);
   base::RunLoop run_loop;
-  delegate_ptr_.set_connection_error_handler(run_loop.QuitClosure());
+  delegate_.set_disconnect_handler(run_loop.QuitClosure());
   host_->Unmount();
   run_loop.Run();
 }
@@ -536,8 +537,8 @@
               GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS))));
 
   base::RunLoop run_loop;
-  delegate_ptr_.set_connection_error_handler(run_loop.QuitClosure());
-  delegate_ptr_->GetAccessToken(
+  delegate_.set_disconnect_handler(run_loop.QuitClosure());
+  delegate_->GetAccessToken(
       "client ID", "app ID", {"scope1", "scope2"},
       base::BindLambdaForTesting([](mojom::AccessTokenStatus status,
                                     const std::string& token) { FAIL(); }));
@@ -564,8 +565,8 @@
   mojom::SyncingStatusPtr observed_status;
   EXPECT_CALL(observer, OnSyncingStatusUpdate(_))
       .WillOnce(CloneStruct(&observed_status));
-  delegate_ptr_->OnSyncingStatusUpdate(status.Clone());
-  delegate_ptr_.FlushForTesting();
+  delegate_->OnSyncingStatusUpdate(status.Clone());
+  delegate_.FlushForTesting();
   testing::Mock::VerifyAndClear(&observer);
 
   EXPECT_EQ(status, observed_status);
@@ -592,8 +593,8 @@
   std::vector<mojom::FileChangePtr> observed_changes;
   EXPECT_CALL(observer, OnFilesChanged(_))
       .WillOnce(CloneVectorOfStructs(&observed_changes));
-  delegate_ptr_->OnFilesChanged(mojo::Clone(changes));
-  delegate_ptr_.FlushForTesting();
+  delegate_->OnFilesChanged(mojo::Clone(changes));
+  delegate_.FlushForTesting();
   testing::Mock::VerifyAndClear(&observer);
 
   EXPECT_EQ(changes, observed_changes);
@@ -608,8 +609,8 @@
       mojom::DriveError::Type::kCantUploadStorageFull, base::FilePath("/foo"));
   mojom::DriveErrorPtr observed_error;
   EXPECT_CALL(observer, OnError(_)).WillOnce(CloneStruct(&observed_error));
-  delegate_ptr_->OnError(error.Clone());
-  delegate_ptr_.FlushForTesting();
+  delegate_->OnError(error.Clone());
+  delegate_.FlushForTesting();
   testing::Mock::VerifyAndClear(&observer);
 
   EXPECT_EQ(error, observed_error);
@@ -621,34 +622,34 @@
   ScopedObserver<DriveFsHost, DriveFsHostObserver> observer_scoper(&observer);
   observer_scoper.Add(host_.get());
   EXPECT_CALL(observer, OnError(_)).Times(0);
-  delegate_ptr_->OnError(mojom::DriveError::New(
+  delegate_->OnError(mojom::DriveError::New(
       static_cast<mojom::DriveError::Type>(
           static_cast<std::underlying_type_t<mojom::DriveError::Type>>(
               mojom::DriveError::Type::kMaxValue) +
           1),
       base::FilePath("/foo")));
-  delegate_ptr_.FlushForTesting();
+  delegate_.FlushForTesting();
 }
 
 TEST_F(DriveFsHostTest, TeamDriveTracking) {
   ASSERT_NO_FATAL_FAILURE(DoMount());
 
-  delegate_ptr_->OnTeamDrivesListReady({"a", "b"});
-  delegate_ptr_.FlushForTesting();
+  delegate_->OnTeamDrivesListReady({"a", "b"});
+  delegate_.FlushForTesting();
   EXPECT_EQ(
       (std::set<std::string>{"a", "b"}),
       host_delegate_->GetDriveNotificationManager().team_drive_ids_for_test());
 
-  delegate_ptr_->OnTeamDriveChanged(
+  delegate_->OnTeamDriveChanged(
       "c", mojom::DriveFsDelegate::CreateOrDelete::kCreated);
-  delegate_ptr_.FlushForTesting();
+  delegate_.FlushForTesting();
   EXPECT_EQ(
       (std::set<std::string>{"a", "b", "c"}),
       host_delegate_->GetDriveNotificationManager().team_drive_ids_for_test());
 
-  delegate_ptr_->OnTeamDriveChanged(
+  delegate_->OnTeamDriveChanged(
       "b", mojom::DriveFsDelegate::CreateOrDelete::kDeleted);
-  delegate_ptr_.FlushForTesting();
+  delegate_.FlushForTesting();
   EXPECT_EQ(
       (std::set<std::string>{"a", "c"}),
       host_delegate_->GetDriveNotificationManager().team_drive_ids_for_test());
@@ -657,8 +658,8 @@
 TEST_F(DriveFsHostTest, Invalidation) {
   ASSERT_NO_FATAL_FAILURE(DoMount());
 
-  delegate_ptr_->OnTeamDrivesListReady({"a", "b"});
-  delegate_ptr_.FlushForTesting();
+  delegate_->OnTeamDrivesListReady({"a", "b"});
+  delegate_.FlushForTesting();
 
   EXPECT_CALL(mock_drivefs_,
               FetchChangeLogImpl(std::vector<std::pair<int64_t, std::string>>{
@@ -668,14 +669,14 @@
        host_delegate_->GetDriveNotificationManager().observers_for_test()) {
     observer.OnNotificationReceived({{"", 123}, {"a", 456}});
   }
-  binding_.FlushForTesting();
+  receiver_.FlushForTesting();
 }
 
 TEST_F(DriveFsHostTest, InvalidateAll) {
   ASSERT_NO_FATAL_FAILURE(DoMount());
 
-  delegate_ptr_->OnTeamDrivesListReady({"a", "b"});
-  delegate_ptr_.FlushForTesting();
+  delegate_->OnTeamDrivesListReady({"a", "b"});
+  delegate_.FlushForTesting();
 
   EXPECT_CALL(mock_drivefs_, FetchAllChangeLogs());
 
@@ -683,14 +684,14 @@
        host_delegate_->GetDriveNotificationManager().observers_for_test()) {
     observer.OnNotificationTimerFired();
   }
-  binding_.FlushForTesting();
+  receiver_.FlushForTesting();
 }
 
 TEST_F(DriveFsHostTest, RemoveDriveNotificationObserver) {
   ASSERT_NO_FATAL_FAILURE(DoMount());
 
-  delegate_ptr_->OnTeamDrivesListReady({"a", "b"});
-  delegate_ptr_.FlushForTesting();
+  delegate_->OnTeamDrivesListReady({"a", "b"});
+  delegate_.FlushForTesting();
   EXPECT_TRUE(host_delegate_->GetDriveNotificationManager()
                   .observers_for_test()
                   .might_have_observers());
@@ -732,7 +733,7 @@
   ASSERT_NO_FATAL_FAILURE(DoMount());
   mock_identity_accessor_.set_pause_requests(true);
 
-  delegate_ptr_->GetAccessToken(
+  delegate_->GetAccessToken(
       "client ID", "app ID", {"scope1", "scope2"},
       base::BindLambdaForTesting([&](mojom::AccessTokenStatus status,
                                      const std::string& token) { FAIL(); }));
@@ -759,7 +760,7 @@
   ASSERT_NO_FATAL_FAILURE(DoMount());
   mock_identity_accessor_.set_pause_requests(true);
 
-  delegate_ptr_->GetAccessToken(
+  delegate_->GetAccessToken(
       "client ID", "app ID", {"scope1", "scope2"},
       base::BindLambdaForTesting([&](mojom::AccessTokenStatus status,
                                      const std::string& token) { FAIL(); }));
diff --git a/chromeos/components/drivefs/drivefs_search.cc b/chromeos/components/drivefs/drivefs_search.cc
index 626f50e4..b510366 100644
--- a/chromeos/components/drivefs/drivefs_search.cc
+++ b/chromeos/components/drivefs/drivefs_search.cc
@@ -4,7 +4,11 @@
 
 #include "chromeos/components/drivefs/drivefs_search.h"
 
+#include <utility>
+
 #include "base/bind.h"
+#include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/network/public/cpp/network_connection_tracker.h"
 
 namespace drivefs {
@@ -44,7 +48,7 @@
     }
   }
 
-  drivefs::mojom::SearchQueryPtr search;
+  mojo::Remote<drivefs::mojom::SearchQuery> search;
   drivefs::mojom::QueryParameters::QuerySource source = query->query_source;
   if (network_connection_tracker_->IsOffline() &&
       source != drivefs::mojom::QueryParameters::QuerySource::kLocalOnly) {
@@ -53,7 +57,8 @@
     OnSearchDriveFs(std::move(search), std::move(query), std::move(callback),
                     drive::FILE_ERROR_NO_CONNECTION, {});
   } else {
-    drivefs_->StartSearchQuery(mojo::MakeRequest(&search), query.Clone());
+    drivefs_->StartSearchQuery(search.BindNewPipeAndPassReceiver(),
+                               query.Clone());
     auto* raw_search = search.get();
     raw_search->GetNextPage(base::BindOnce(
         &DriveFsSearch::OnSearchDriveFs, weak_ptr_factory_.GetWeakPtr(),
@@ -63,7 +68,7 @@
 }
 
 void DriveFsSearch::OnSearchDriveFs(
-    drivefs::mojom::SearchQueryPtr search,
+    mojo::Remote<drivefs::mojom::SearchQuery> search,
     drivefs::mojom::QueryParametersPtr query,
     mojom::SearchQuery::GetNextPageCallback callback,
     drive::FileError error,
diff --git a/chromeos/components/drivefs/drivefs_search.h b/chromeos/components/drivefs/drivefs_search.h
index d3fbbe4..f9f4853 100644
--- a/chromeos/components/drivefs/drivefs_search.h
+++ b/chromeos/components/drivefs/drivefs_search.h
@@ -14,6 +14,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/clock.h"
 #include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace network {
 class NetworkConnectionTracker;
@@ -37,7 +38,7 @@
 
  private:
   void OnSearchDriveFs(
-      drivefs::mojom::SearchQueryPtr search,
+      mojo::Remote<drivefs::mojom::SearchQuery> search,
       drivefs::mojom::QueryParametersPtr query,
       mojom::SearchQuery::GetNextPageCallback callback,
       drive::FileError error,
diff --git a/chromeos/components/drivefs/drivefs_search_unittest.cc b/chromeos/components/drivefs/drivefs_search_unittest.cc
index 8b863e6..4e48fa8c 100644
--- a/chromeos/components/drivefs/drivefs_search_unittest.cc
+++ b/chromeos/components/drivefs/drivefs_search_unittest.cc
@@ -4,12 +4,16 @@
 
 #include "chromeos/components/drivefs/drivefs_search.h"
 
+#include <utility>
+
 #include "base/run_loop.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/simple_test_clock.h"
 #include "base/test/task_environment.h"
 #include "chromeos/components/drivefs/mojom/drivefs.mojom-test-utils.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -22,7 +26,7 @@
 class MockDriveFs : public mojom::DriveFsInterceptorForTesting,
                     public mojom::SearchQuery {
  public:
-  MockDriveFs() : search_binding_(this) {}
+  MockDriveFs() = default;
 
   DriveFs* GetForwardingInterface() override {
     NOTREACHED();
@@ -30,12 +34,11 @@
   }
 
   MOCK_CONST_METHOD1(OnStartSearchQuery, void(const mojom::QueryParameters&));
-  void StartSearchQuery(mojom::SearchQueryRequest query,
+  void StartSearchQuery(mojo::PendingReceiver<mojom::SearchQuery> receiver,
                         mojom::QueryParametersPtr query_params) override {
-    if (search_binding_.is_bound())
-      search_binding_.Unbind();
+    search_receiver_.reset();
     OnStartSearchQuery(*query_params);
-    search_binding_.Bind(std::move(query));
+    search_receiver_.Bind(std::move(receiver));
   }
 
   MOCK_METHOD1(OnGetNextPage,
@@ -49,7 +52,7 @@
   }
 
  private:
-  mojo::Binding<mojom::SearchQuery> search_binding_;
+  mojo::Receiver<mojom::SearchQuery> search_receiver_{this};
   DISALLOW_COPY_AND_ASSIGN(MockDriveFs);
 };
 
diff --git a/chromeos/components/drivefs/fake_drivefs.cc b/chromeos/components/drivefs/fake_drivefs.cc
index aadcc63..e516bc0 100644
--- a/chromeos/components/drivefs/fake_drivefs.cc
+++ b/chromeos/components/drivefs/fake_drivefs.cc
@@ -20,9 +20,12 @@
 #include "base/task/post_task.h"
 #include "base/threading/thread_restrictions.h"
 #include "chromeos/components/drivefs/drivefs_util.h"
+#include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cros_disks_client.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 
 namespace drivefs {
 namespace {
@@ -70,15 +73,16 @@
 }  // namespace
 
 FakeDriveFsBootstrapListener::FakeDriveFsBootstrapListener(
-    drivefs::mojom::DriveFsBootstrapPtrInfo bootstrap)
+    mojo::PendingRemote<drivefs::mojom::DriveFsBootstrap> bootstrap)
     : bootstrap_(std::move(bootstrap)) {}
 
 FakeDriveFsBootstrapListener::~FakeDriveFsBootstrapListener() = default;
 
 void FakeDriveFsBootstrapListener::SendInvitationOverPipe(base::ScopedFD) {}
 
-mojom::DriveFsBootstrapPtr FakeDriveFsBootstrapListener::bootstrap() {
-  return mojo::MakeProxy(std::move(bootstrap_));
+mojo::PendingRemote<mojom::DriveFsBootstrap>
+FakeDriveFsBootstrapListener::bootstrap() {
+  return std::move(bootstrap_);
 }
 
 struct FakeDriveFs::FileMetadata {
@@ -227,7 +231,7 @@
 };
 
 FakeDriveFs::FakeDriveFs(const base::FilePath& mount_path)
-    : mount_path_(mount_path), binding_(this), bootstrap_binding_(this) {
+    : mount_path_(mount_path) {
   CHECK(mount_path.IsAbsolute());
   CHECK(!mount_path.ReferencesParent());
 }
@@ -248,13 +252,13 @@
 
 std::unique_ptr<drivefs::DriveFsBootstrapListener>
 FakeDriveFs::CreateMojoListener() {
-  drivefs::mojom::DriveFsBootstrapPtrInfo bootstrap;
-  if (bootstrap_binding_.is_bound())
-    bootstrap_binding_.Unbind();
-  bootstrap_binding_.Bind(mojo::MakeRequest(&bootstrap));
-  pending_delegate_request_ = mojo::MakeRequest(&delegate_);
+  delegate_.reset();
+  pending_delegate_receiver_ = delegate_.BindNewPipeAndPassReceiver();
   delegate_->OnMounted();
-  return std::make_unique<FakeDriveFsBootstrapListener>(std::move(bootstrap));
+
+  bootstrap_receiver_.reset();
+  return std::make_unique<FakeDriveFsBootstrapListener>(
+      bootstrap_receiver_.BindNewPipeAndPassRemote());
 }
 
 void FakeDriveFs::SetMetadata(const base::FilePath& path,
@@ -278,18 +282,17 @@
   }
 }
 
-void FakeDriveFs::Init(drivefs::mojom::DriveFsConfigurationPtr config,
-                       drivefs::mojom::DriveFsRequest drive_fs_request,
-                       drivefs::mojom::DriveFsDelegatePtr delegate) {
+void FakeDriveFs::Init(
+    drivefs::mojom::DriveFsConfigurationPtr config,
+    mojo::PendingReceiver<drivefs::mojom::DriveFs> receiver,
+    mojo::PendingRemote<drivefs::mojom::DriveFsDelegate> delegate) {
   {
     base::ScopedAllowBlockingForTesting allow_io;
     CHECK(base::CreateDirectory(mount_path_.Append(".Trash")));
   }
-  mojo::FuseInterface(std::move(pending_delegate_request_),
-                      delegate.PassInterface());
-  if (binding_.is_bound())
-    binding_.Unbind();
-  binding_.Bind(std::move(drive_fs_request));
+  mojo::FusePipes(std::move(pending_delegate_receiver_), std::move(delegate));
+  receiver_.reset();
+  receiver_.Bind(std::move(receiver));
 }
 
 void FakeDriveFs::GetMetadata(const base::FilePath& path,
@@ -401,11 +404,11 @@
 }
 
 void FakeDriveFs::StartSearchQuery(
-    drivefs::mojom::SearchQueryRequest query,
+    mojo::PendingReceiver<drivefs::mojom::SearchQuery> receiver,
     drivefs::mojom::QueryParametersPtr query_params) {
   auto search_query = std::make_unique<SearchQuery>(weak_factory_.GetWeakPtr(),
                                                     std::move(query_params));
-  mojo::MakeStrongBinding(std::move(search_query), std::move(query));
+  mojo::MakeSelfOwnedReceiver(std::move(search_query), std::move(receiver));
 }
 
 void FakeDriveFs::FetchAllChangeLogs() {}
diff --git a/chromeos/components/drivefs/fake_drivefs.h b/chromeos/components/drivefs/fake_drivefs.h
index 2e22b80..389a9aa 100644
--- a/chromeos/components/drivefs/fake_drivefs.h
+++ b/chromeos/components/drivefs/fake_drivefs.h
@@ -16,21 +16,24 @@
 #include "chromeos/components/drivefs/drivefs_bootstrap.h"
 #include "chromeos/components/drivefs/drivefs_host.h"
 #include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace drivefs {
 
 class FakeDriveFsBootstrapListener : public DriveFsBootstrapListener {
  public:
   explicit FakeDriveFsBootstrapListener(
-      drivefs::mojom::DriveFsBootstrapPtrInfo bootstrap);
+      mojo::PendingRemote<drivefs::mojom::DriveFsBootstrap> bootstrap);
   ~FakeDriveFsBootstrapListener() override;
 
  private:
   void SendInvitationOverPipe(base::ScopedFD) override;
-  mojom::DriveFsBootstrapPtr bootstrap() override;
+  mojo::PendingRemote<mojom::DriveFsBootstrap> bootstrap() override;
 
-  drivefs::mojom::DriveFsBootstrapPtrInfo bootstrap_;
+  mojo::PendingRemote<drivefs::mojom::DriveFsBootstrap> bootstrap_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeDriveFsBootstrapListener);
 };
@@ -61,9 +64,10 @@
   class SearchQuery;
 
   // drivefs::mojom::DriveFsBootstrap:
-  void Init(drivefs::mojom::DriveFsConfigurationPtr config,
-            drivefs::mojom::DriveFsRequest drive_fs_request,
-            drivefs::mojom::DriveFsDelegatePtr delegate) override;
+  void Init(
+      drivefs::mojom::DriveFsConfigurationPtr config,
+      mojo::PendingReceiver<drivefs::mojom::DriveFs> receiver,
+      mojo::PendingRemote<drivefs::mojom::DriveFsDelegate> delegate) override;
 
   // drivefs::mojom::DriveFs:
   void GetMetadata(const base::FilePath& path,
@@ -86,7 +90,7 @@
                 CopyFileCallback callback) override;
 
   void StartSearchQuery(
-      drivefs::mojom::SearchQueryRequest query,
+      mojo::PendingReceiver<drivefs::mojom::SearchQuery> receiver,
       drivefs::mojom::QueryParametersPtr query_params) override;
 
   void FetchAllChangeLogs() override;
@@ -98,10 +102,11 @@
 
   std::map<base::FilePath, FileMetadata> metadata_;
 
-  mojo::Binding<drivefs::mojom::DriveFs> binding_;
-  drivefs::mojom::DriveFsDelegatePtr delegate_;
-  mojo::Binding<drivefs::mojom::DriveFsBootstrap> bootstrap_binding_;
-  drivefs::mojom::DriveFsDelegateRequest pending_delegate_request_;
+  mojo::Receiver<drivefs::mojom::DriveFs> receiver_{this};
+  mojo::Remote<drivefs::mojom::DriveFsDelegate> delegate_;
+  mojo::Receiver<drivefs::mojom::DriveFsBootstrap> bootstrap_receiver_{this};
+  mojo::PendingReceiver<drivefs::mojom::DriveFsDelegate>
+      pending_delegate_receiver_;
 
   base::WeakPtrFactory<FakeDriveFs> weak_factory_{this};
 
diff --git a/chromeos/components/drivefs/mojom/drivefs.mojom b/chromeos/components/drivefs/mojom/drivefs.mojom
index 06792c49..664c95db 100644
--- a/chromeos/components/drivefs/mojom/drivefs.mojom
+++ b/chromeos/components/drivefs/mojom/drivefs.mojom
@@ -14,8 +14,8 @@
 interface DriveFsBootstrap {
   // Initialize a DriveFS instance with its configuration and mojo connections
   // to the browser.
-  Init(DriveFsConfiguration config, DriveFs& drive_fs,
-       DriveFsDelegate delegate);
+  Init(DriveFsConfiguration config, pending_receiver<DriveFs> drive_fs,
+       pending_remote<DriveFsDelegate> delegate);
 };
 
 // Implemented by DriveFS, used from Chrome.
@@ -49,7 +49,8 @@
       (FileError error);
 
   // Start a search query with given parameters.
-  StartSearchQuery(SearchQuery& query, QueryParameters query_params);
+  StartSearchQuery(pending_receiver<SearchQuery> query,
+                   QueryParameters query_params);
 
   // Fetches all changelogs, i.e. for My Drive and all Team Drives.
   FetchAllChangeLogs();
diff --git a/chromeos/dbus/cicerone_client.cc b/chromeos/dbus/cicerone_client.cc
index 8e5928a..e6b9096e 100644
--- a/chromeos/dbus/cicerone_client.cc
+++ b/chromeos/dbus/cicerone_client.cc
@@ -94,10 +94,6 @@
     return is_apply_ansible_playbook_progress_signal_connected_;
   }
 
-  bool IsUpgradeContainerProgressSignalConnected() override {
-    return is_upgrade_container_progress_signal_connected_;
-  }
-
   void LaunchContainerApplication(
       const vm_tools::cicerone::LaunchContainerApplicationRequest& request,
       DBusMethodCallback<vm_tools::cicerone::LaunchContainerApplicationResponse>
@@ -444,51 +440,6 @@
                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   }
 
-  void UpgradeContainer(
-      const vm_tools::cicerone::UpgradeContainerRequest& request,
-      DBusMethodCallback<vm_tools::cicerone::UpgradeContainerResponse> callback)
-      override {
-    dbus::MethodCall method_call(vm_tools::cicerone::kVmCiceroneInterface,
-                                 vm_tools::cicerone::kUpgradeContainerMethod);
-    dbus::MessageWriter writer(&method_call);
-
-    if (!writer.AppendProtoAsArrayOfBytes(request)) {
-      LOG(ERROR) << "Failed to encode UpgradeContainerRequest protobuf";
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
-      return;
-    }
-
-    cicerone_proxy_->CallMethod(
-        &method_call, kDefaultTimeout.InMilliseconds(),
-        base::BindOnce(&CiceroneClientImpl::OnDBusProtoResponse<
-                           vm_tools::cicerone::UpgradeContainerResponse>,
-                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-  }
-
-  void CancelUpgradeContainer(
-      const vm_tools::cicerone::CancelUpgradeContainerRequest& request,
-      DBusMethodCallback<vm_tools::cicerone::CancelUpgradeContainerResponse>
-          callback) override {
-    dbus::MethodCall method_call(
-        vm_tools::cicerone::kVmCiceroneInterface,
-        vm_tools::cicerone::kCancelUpgradeContainerMethod);
-    dbus::MessageWriter writer(&method_call);
-
-    if (!writer.AppendProtoAsArrayOfBytes(request)) {
-      LOG(ERROR) << "Failed to encode CancelUpgradeContainerRequest protobuf";
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
-      return;
-    }
-
-    cicerone_proxy_->CallMethod(
-        &method_call, kDefaultTimeout.InMilliseconds(),
-        base::BindOnce(&CiceroneClientImpl::OnDBusProtoResponse<
-                           vm_tools::cicerone::CancelUpgradeContainerResponse>,
-                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-  }
-
   void WaitForServiceToBeAvailable(
       dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback)
       override {
@@ -601,15 +552,6 @@
             weak_ptr_factory_.GetWeakPtr()),
         base::BindOnce(&CiceroneClientImpl::OnSignalConnected,
                        weak_ptr_factory_.GetWeakPtr()));
-
-    cicerone_proxy_->ConnectToSignal(
-        vm_tools::cicerone::kVmCiceroneInterface,
-        vm_tools::cicerone::kUpgradeContainerProgressSignal,
-        base::BindRepeating(
-            &CiceroneClientImpl::OnUpgradeContainerProgressSignal,
-            weak_ptr_factory_.GetWeakPtr()),
-        base::BindOnce(&CiceroneClientImpl::OnSignalConnected,
-                       weak_ptr_factory_.GetWeakPtr()));
   }
 
  private:
@@ -786,24 +728,12 @@
     }
   }
 
-  void OnUpgradeContainerProgressSignal(dbus::Signal* signal) {
-    vm_tools::cicerone::UpgradeContainerProgressSignal proto;
-    dbus::MessageReader reader(signal);
-    if (!reader.PopArrayOfBytesAsProto(&proto)) {
-      LOG(ERROR) << "Failed to parse proto from DBus Signal";
-      return;
-    }
-    for (auto& observer : observer_list_) {
-      observer.OnUpgradeContainerProgress(proto);
-    }
-  }
-
   void OnSignalConnected(const std::string& interface_name,
                          const std::string& signal_name,
                          bool is_connected) {
     if (!is_connected) {
       LOG(ERROR)
-          << "Failed to connect to Signal. Async container ops may not work";
+          << "Failed to connect to Signal. Async StartContainer will not work";
     }
     DCHECK_EQ(interface_name, vm_tools::cicerone::kVmCiceroneInterface);
     if (signal_name == vm_tools::cicerone::kContainerStartedSignal) {
@@ -839,9 +769,6 @@
     } else if (signal_name ==
                vm_tools::cicerone::kApplyAnsiblePlaybookProgressSignal) {
       is_apply_ansible_playbook_progress_signal_connected_ = is_connected;
-    } else if (signal_name ==
-               vm_tools::cicerone::kUpgradeContainerProgressSignal) {
-      is_upgrade_container_progress_signal_connected_ = is_connected;
     } else {
       NOTREACHED();
     }
@@ -864,7 +791,6 @@
   bool is_import_lxd_container_progress_signal_connected_ = false;
   bool is_pending_app_list_updates_signal_connected_ = false;
   bool is_apply_ansible_playbook_progress_signal_connected_ = false;
-  bool is_upgrade_container_progress_signal_connected_ = false;
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
diff --git a/chromeos/dbus/cicerone_client.h b/chromeos/dbus/cicerone_client.h
index 3fdce4a..bacf22b 100644
--- a/chromeos/dbus/cicerone_client.h
+++ b/chromeos/dbus/cicerone_client.h
@@ -89,11 +89,6 @@
         const vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal&
             signal) = 0;
 
-    // This is signaled from Cicerone while a container is being upgraded
-    // via UpgradeContainer.
-    virtual void OnUpgradeContainerProgress(
-        const vm_tools::cicerone::UpgradeContainerProgressSignal& signal) = 0;
-
    protected:
     virtual ~Observer() = default;
   };
@@ -151,9 +146,6 @@
   // This should be true prior to calling ApplyAnsiblePlaybook.
   virtual bool IsApplyAnsiblePlaybookProgressSignalConnected() = 0;
 
-  // This should be true prior to calling UpgradeContainer.
-  virtual bool IsUpgradeContainerProgressSignalConnected() = 0;
-
   // Launches an application inside a running Container.
   // |callback| is called after the method call finishes.
   virtual void LaunchContainerApplication(
@@ -262,20 +254,6 @@
       DBusMethodCallback<vm_tools::cicerone::ApplyAnsiblePlaybookResponse>
           callback) = 0;
 
-  // Upgrades the container.
-  // |callback| is called when the method completes.
-  virtual void UpgradeContainer(
-      const vm_tools::cicerone::UpgradeContainerRequest& request,
-      DBusMethodCallback<vm_tools::cicerone::UpgradeContainerResponse>
-          callback) = 0;
-
-  // Cancels the in progress container upgrade.
-  // |callback| is called when the method completes.
-  virtual void CancelUpgradeContainer(
-      const vm_tools::cicerone::CancelUpgradeContainerRequest& request,
-      DBusMethodCallback<vm_tools::cicerone::CancelUpgradeContainerResponse>
-          callback) = 0;
-
   // Registers |callback| to run when the Cicerone service becomes available.
   // If the service is already available, or if connecting to the name-owner-
   // changed signal fails, |callback| will be run once asynchronously.
diff --git a/chromeos/dbus/fake_cicerone_client.cc b/chromeos/dbus/fake_cicerone_client.cc
index 2ba8b76f..456a415b 100644
--- a/chromeos/dbus/fake_cicerone_client.cc
+++ b/chromeos/dbus/fake_cicerone_client.cc
@@ -38,12 +38,6 @@
 
   import_lxd_container_response_.set_status(
       vm_tools::cicerone::ImportLxdContainerResponse::IMPORTING);
-
-  upgrade_container_response_.set_status(
-      vm_tools::cicerone::UpgradeContainerResponse::STARTED);
-
-  cancel_upgrade_container_response_.set_status(
-      vm_tools::cicerone::CancelUpgradeContainerResponse::CANCELLED);
 }
 
 FakeCiceroneClient::~FakeCiceroneClient() = default;
@@ -104,10 +98,6 @@
   return is_apply_ansible_playbook_progress_signal_connected_;
 }
 
-bool FakeCiceroneClient::IsUpgradeContainerProgressSignalConnected() {
-  return is_upgrade_container_progress_signal_connected_;
-}
-
 // Currently no tests need to change the output of this method. If you want to
 // add one, make it return a variable like the above examples.
 bool FakeCiceroneClient::IsPendingAppListUpdatesSignalConnected() {
@@ -301,23 +291,6 @@
       base::BindOnce(std::move(callback), apply_ansible_playbook_response_));
 }
 
-void FakeCiceroneClient::UpgradeContainer(
-    const vm_tools::cicerone::UpgradeContainerRequest& request,
-    DBusMethodCallback<vm_tools::cicerone::UpgradeContainerResponse> callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(std::move(callback), upgrade_container_response_));
-}
-
-void FakeCiceroneClient::CancelUpgradeContainer(
-    const vm_tools::cicerone::CancelUpgradeContainerRequest& request,
-    DBusMethodCallback<vm_tools::cicerone::CancelUpgradeContainerResponse>
-        callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(std::move(callback), cancel_upgrade_container_response_));
-}
-
 void FakeCiceroneClient::NotifyLxdContainerCreated(
     const vm_tools::cicerone::LxdContainerCreatedSignal& proto) {
   for (auto& observer : observer_list_) {
@@ -388,11 +361,4 @@
   }
 }
 
-void FakeCiceroneClient::NotifyUpgradeContainerProgress(
-    const vm_tools::cicerone::UpgradeContainerProgressSignal& signal) {
-  for (auto& observer : observer_list_) {
-    observer.OnUpgradeContainerProgress(signal);
-  }
-}
-
 }  // namespace chromeos
diff --git a/chromeos/dbus/fake_cicerone_client.h b/chromeos/dbus/fake_cicerone_client.h
index 2614ce0a..47f6d0c7 100644
--- a/chromeos/dbus/fake_cicerone_client.h
+++ b/chromeos/dbus/fake_cicerone_client.h
@@ -38,7 +38,6 @@
   bool IsImportLxdContainerProgressSignalConnected() override;
   bool IsPendingAppListUpdatesSignalConnected() override;
   bool IsApplyAnsiblePlaybookProgressSignalConnected() override;
-  bool IsUpgradeContainerProgressSignalConnected() override;
   void LaunchContainerApplication(
       const vm_tools::cicerone::LaunchContainerApplicationRequest& request,
       DBusMethodCallback<vm_tools::cicerone::LaunchContainerApplicationResponse>
@@ -106,14 +105,6 @@
       const vm_tools::cicerone::ApplyAnsiblePlaybookRequest& request,
       DBusMethodCallback<vm_tools::cicerone::ApplyAnsiblePlaybookResponse>
           callback) override;
-  void UpgradeContainer(
-      const vm_tools::cicerone::UpgradeContainerRequest& request,
-      DBusMethodCallback<vm_tools::cicerone::UpgradeContainerResponse> callback)
-      override;
-  void CancelUpgradeContainer(
-      const vm_tools::cicerone::CancelUpgradeContainerRequest& request,
-      DBusMethodCallback<vm_tools::cicerone::CancelUpgradeContainerResponse>
-          callback) override;
   void WaitForServiceToBeAvailable(
       dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) override;
 
@@ -161,9 +152,6 @@
   void set_import_lxd_container_progress_signal_connected(bool connected) {
     is_import_lxd_container_progress_signal_connected_ = connected;
   }
-  void set_upgrade_container_progress_signal_connected(bool connected) {
-    is_upgrade_container_progress_signal_connected_ = connected;
-  }
   void set_launch_container_application_response(
       const vm_tools::cicerone::LaunchContainerApplicationResponse&
           launch_container_application_response) {
@@ -257,16 +245,6 @@
           apply_ansible_playbook_response) {
     apply_ansible_playbook_response_ = apply_ansible_playbook_response;
   }
-  void set_upgrade_container_response(
-      vm_tools::cicerone::UpgradeContainerResponse upgrade_container_response) {
-    upgrade_container_response_ = std::move(upgrade_container_response);
-  }
-  void set_cancel_upgrade_container_response(
-      vm_tools::cicerone::CancelUpgradeContainerResponse
-          cancel_upgrade_container_response) {
-    cancel_upgrade_container_response_ =
-        std::move(cancel_upgrade_container_response);
-  }
 
   // Additional functions to allow tests to trigger Signals.
   void NotifyLxdContainerCreated(
@@ -291,8 +269,6 @@
       const vm_tools::cicerone::PendingAppListUpdatesSignal& signal);
   void NotifyApplyAnsiblePlaybookProgress(
       const vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal& signal);
-  void NotifyUpgradeContainerProgress(
-      const vm_tools::cicerone::UpgradeContainerProgressSignal& signal);
 
  protected:
   void Init(dbus::Bus* bus) override {}
@@ -310,7 +286,6 @@
   bool is_export_lxd_container_progress_signal_connected_ = true;
   bool is_import_lxd_container_progress_signal_connected_ = true;
   bool is_apply_ansible_playbook_progress_signal_connected_ = true;
-  bool is_upgrade_container_progress_signal_connected_ = true;
 
   std::string last_container_username_;
   bool send_container_started_signal_ = true;
@@ -352,9 +327,6 @@
       cancel_import_lxd_container_response_;
   vm_tools::cicerone::ApplyAnsiblePlaybookResponse
       apply_ansible_playbook_response_;
-  vm_tools::cicerone::UpgradeContainerResponse upgrade_container_response_;
-  vm_tools::cicerone::CancelUpgradeContainerResponse
-      cancel_upgrade_container_response_;
 
   vm_tools::cicerone::OsRelease lxd_container_os_release_;
 
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.cc b/chromeos/services/assistant/assistant_manager_service_impl.cc
index b1debae..2e9db3e 100644
--- a/chromeos/services/assistant/assistant_manager_service_impl.cc
+++ b/chromeos/services/assistant/assistant_manager_service_impl.cc
@@ -171,7 +171,7 @@
   client->RequestMediaControllerManager(
       media_controller_manager.BindNewPipeAndPassReceiver());
   media_controller_manager->CreateActiveMediaController(
-      mojo::MakeRequest(&media_controller_));
+      media_controller_.BindNewPipeAndPassReceiver());
 }
 
 AssistantManagerServiceImpl::~AssistantManagerServiceImpl() {
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.h b/chromeos/services/assistant/assistant_manager_service_impl.h
index 3aa5c20..eddcf5a 100644
--- a/chromeos/services/assistant/assistant_manager_service_impl.h
+++ b/chromeos/services/assistant/assistant_manager_service_impl.h
@@ -28,6 +28,7 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/bindings/remote_set.h"
 #include "services/device/public/mojom/battery_monitor.mojom.h"
 #include "services/media_session/public/mojom/media_controller.mojom.h"
@@ -342,7 +343,7 @@
       nullptr;
   mojo::RemoteSet<mojom::AssistantInteractionSubscriber>
       interaction_subscribers_;
-  media_session::mojom::MediaControllerPtr media_controller_;
+  mojo::Remote<media_session::mojom::MediaController> media_controller_;
 
   // Owned by the parent |Service| which will destroy |this| before |context_|.
   ServiceContext* const context_;
diff --git a/chromeos/services/ime/public/cpp/BUILD.gn b/chromeos/services/ime/public/cpp/BUILD.gn
index 83bbc285..7205512 100644
--- a/chromeos/services/ime/public/cpp/BUILD.gn
+++ b/chromeos/services/ime/public/cpp/BUILD.gn
@@ -4,6 +4,8 @@
 
 import("//build/buildflag_header.gni")
 import("//chromeos/services/ime/public/features.gni")
+import("//testing/libfuzzer/fuzzer_test.gni")
+import("//third_party/libprotobuf-mutator/fuzzable_proto_library.gni")
 
 buildflag_header("buildflags") {
   header = "buildflags.h"
@@ -106,3 +108,23 @@
     "rulebased/rulebased_unittest.cc",
   ]
 }
+
+if (use_libfuzzer) {
+  fuzzable_proto_library("rulebased_fuzzer_proto") {
+    sources = [
+      "rulebased/rulebased_fuzzer.proto",
+    ]
+  }
+
+  fuzzer_test("rulebased_fuzzer") {
+    sources = [
+      "rulebased/rulebased_fuzzer.cc",
+    ]
+    seed_corpus = "rulebased/test_data"
+    deps = [
+      ":rulebased",
+      ":rulebased_fuzzer_proto",
+      "//third_party/libprotobuf-mutator",
+    ]
+  }
+}
diff --git a/chromeos/services/ime/public/cpp/rulebased/rulebased_fuzzer.cc b/chromeos/services/ime/public/cpp/rulebased/rulebased_fuzzer.cc
new file mode 100644
index 0000000..7311199a
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/rulebased_fuzzer.cc
@@ -0,0 +1,92 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/stl_util.h"
+#include "chromeos/services/ime/public/cpp/rulebased/def/us.h"
+#include "chromeos/services/ime/public/cpp/rulebased/engine.h"
+#include "chromeos/services/ime/public/cpp/rulebased/rulebased_fuzzer.pb.h"
+#include "chromeos/services/ime/public/cpp/rulebased/rules_data.h"
+#include "testing/libfuzzer/proto/lpm_interface.h"
+
+namespace rulebased = chromeos::ime::rulebased;
+
+namespace {
+
+// Must match chromeos/services/ime/public/cpp/rulebased/rulebased_fuzzer.proto
+constexpr const char* kKeyCodes[] = {
+    "Backquote",    "Digit1", "Digit2",    "Digit3",        "Digit4",
+    "Digit5",       "Digit6", "Digit7",    "Digit8",        "Digit9",
+    "Digit0",       "Minus",  "Equal",     "Backspace",     "KeyQ",
+    "KeyW",         "KeyE",   "KeyR",      "KeyT",          "KeyY",
+    "KeyU",         "KeyI",   "KeyO",      "KeyP",          "BracketLeft",
+    "BracketRight", "KeyA",   "KeyS",      "KeyD",          "KeyF",
+    "KeyG",         "KeyH",   "KeyJ",      "KeyK",          "KeyL",
+    "Semicolon",    "Quote",  "Backslash", "IntlBackslash", "Enter",
+    "KeyZ",         "KeyX",   "KeyC",      "KeyV",          "KeyB",
+    "KeyN",         "KeyM",   "Comma",     "Period",        "Slash",
+    "Space"};
+
+// Must match chromeos/services/ime/public/cpp/rulebased/rulebased_fuzzer.proto
+constexpr const char* kEngineIds[] = {
+    "ar",
+    "bn_phone",
+    "ckb_ar",
+    "ckb_en",
+    "deva_phone",
+    "ethi",
+    "fa",
+    "gu_phone",
+    "km",
+    "kn_phone",
+    "lo",
+    "ml_phone",
+    "my",
+    "my_myansan",
+    "ne_inscript",
+    "ne_phone",
+    "ru_phone_aatseel",
+    "ru_phone_yazhert",
+    "si",
+    "ta_inscript",
+    "ta_itrans",
+    "ta_phone",
+    "ta_tamil99",
+    "ta_typewriter",
+    "te_phone",
+    "th",
+    "th_pattajoti",
+    "th_tis",
+    "us",
+    "vi_tcvn",
+    "vi_telex",
+    "vi_viqr",
+    "vi_vni",
+};
+
+static rulebased::Engine engines[base::size(kEngineIds)];
+
+uint8_t GetModifierFromKeyEvent(const rulebased_fuzzer::KeyEvent& e) {
+  uint8_t modifiers = 0;
+  if (e.shift())
+    modifiers |= rulebased::MODIFIER_SHIFT;
+  if (e.altgr())
+    modifiers |= rulebased::MODIFIER_ALTGR;
+  if (e.caps_lock())
+    modifiers |= rulebased::MODIFIER_CAPSLOCK;
+  return modifiers;
+}
+
+}  // namespace
+
+DEFINE_PROTO_FUZZER(const rulebased_fuzzer::TestFuzzerInput& msg) {
+  auto& engine = engines[msg.engine_id()];
+  engine.Activate(kEngineIds[msg.engine_id()]);
+
+  for (const auto& event : msg.key_events()) {
+    engine.ProcessKey(kKeyCodes[event.code()], GetModifierFromKeyEvent(event));
+  }
+}
diff --git a/chromeos/services/ime/public/cpp/rulebased/rulebased_fuzzer.proto b/chromeos/services/ime/public/cpp/rulebased/rulebased_fuzzer.proto
new file mode 100644
index 0000000..fcd4df6b
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/rulebased_fuzzer.proto
@@ -0,0 +1,109 @@
+syntax = "proto2";
+
+package rulebased_fuzzer;
+
+// If you change this enum, please update the corresponding array in
+// //chromeos/services/ime/public/cpp/rulebased/rulebased_fuzzer.cc
+enum KeyCode {
+  BACKQUOTE = 0;
+  DIGIT1 = 1;
+  DIGIT2 = 2;
+  DIGIT3 = 3;
+  DIGIT4 = 4;
+  DIGIT5 = 5;
+  DIGIT6 = 6;
+  DIGIT7 = 7;
+  DIGIT8 = 8;
+  DIGIT9 = 9;
+  DIGIT0 = 10;
+  MINUS = 11;
+  EQUAL = 12;
+  BACKSPACE = 13;
+  KEY_Q = 14;
+  KEY_W = 15;
+  KEY_E = 16;
+  KEY_R = 17;
+  KEY_T = 18;
+  KEY_Y = 19;
+  KEY_U = 20;
+  KEY_I = 21;
+  KEY_O = 22;
+  KEY_P = 23;
+  BRACKET_LEFT = 24;
+  BRACKET_RIGHT = 25;
+  KEY_A = 26;
+  KEY_S = 27;
+  KEY_D = 28;
+  KEY_F = 29;
+  KEY_G = 30;
+  KEY_H = 31;
+  KEY_J = 32;
+  KEY_K = 33;
+  KEY_L = 34;
+  SEMICOLON = 35;
+  QUOTE = 36;
+  BACKSLASH = 37;
+  INTL_BACKSLASH = 38;
+  ENTER = 39;
+  KEY_Z = 40;
+  KEY_X = 41;
+  KEY_C = 42;
+  KEY_V = 43;
+  KEY_B = 44;
+  KEY_N = 45;
+  KEY_M = 46;
+  COMMA = 47;
+  PERIOD = 48;
+  SLASH = 49;
+  SPACE = 50;
+}
+
+// If you change this enum, please update the corresponding array in
+// //chromeos/services/ime/public/cpp/rulebased/rulebased_fuzzer.cc
+enum EngineId {
+  AR = 0;
+  BN_PHONE = 1;
+  CKB_AR = 2;
+  CKB_EN = 3;
+  DEVA_PHONE = 4;
+  ETHI = 5;
+  FA = 6;
+  GU_PHONE = 7;
+  KM = 8;
+  KN_PHONE = 9;
+  LO = 10;
+  ML_PHONE = 11;
+  MY = 12;
+  MY_MYANSAN = 13;
+  NE_INSCRIPT = 14;
+  NE_PHONE = 15;
+  RU_PHONE_AATSEEL = 16;
+  RU_PHONE_YAZHERT = 17;
+  SI = 18;
+  TA_INSCRIPT = 19;
+  TA_ITRANS = 20;
+  TA_PHONE = 21;
+  TA_TAMIL99 = 22;
+  TA_TYPEWRITER = 23;
+  TE_PHONE = 24;
+  TH = 25;
+  TH_PATTAJOTI = 26;
+  TH_TIS = 27;
+  US = 28;
+  VI_TCVN = 29;
+  VI_TELEX = 30;
+  VI_VIQR = 31;
+  VI_VNI = 32;
+}
+
+message KeyEvent {
+  required KeyCode code = 1;
+  required bool shift = 2;
+  required bool altgr = 3;
+  required bool caps_lock = 4;
+}
+
+message TestFuzzerInput {
+  required EngineId engine_id = 1;
+  repeated KeyEvent key_events = 2;
+}
diff --git a/chromeos/services/ime/public/cpp/rulebased/test_data/arabic b/chromeos/services/ime/public/cpp/rulebased/test_data/arabic
new file mode 100644
index 0000000..08e9fb7
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/test_data/arabic
@@ -0,0 +1,20 @@
+# Created from RulebasedImeTest.Arabic
+engine_id: AR
+key_events {
+  code: KEY_A
+  shift: true
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: KEY_B
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: SPACE
+  shift: false
+  altgr: false
+  caps_lock: false
+}
diff --git a/chromeos/services/ime/public/cpp/rulebased/test_data/deva_phone b/chromeos/services/ime/public/cpp/rulebased/test_data/deva_phone
new file mode 100644
index 0000000..c78d2a3
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/test_data/deva_phone
@@ -0,0 +1,14 @@
+# Created from RulebasedImeTest.DevaPhone
+engine_id: DEVA_PHONE
+key_events {
+  code: KEY_A
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: KEY_A
+  shift: false
+  altgr: true
+  caps_lock: false
+}
diff --git a/chromeos/services/ime/public/cpp/rulebased/test_data/deva_phone_backspace b/chromeos/services/ime/public/cpp/rulebased/test_data/deva_phone_backspace
new file mode 100644
index 0000000..092fd1e
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/test_data/deva_phone_backspace
@@ -0,0 +1,62 @@
+# Created from RulebasedImeTest.DevaPhone_Backspace
+engine_id: DEVA_PHONE
+key_events {
+  code: KEY_N
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: BACKSPACE
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: KEY_N
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: KEY_C
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: BACKSPACE
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: KEY_C
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: KEY_H
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: BACKSPACE
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: BACKSPACE
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: BACKSPACE
+  shift: false
+  altgr: false
+  caps_lock: false
+}
diff --git a/chromeos/services/ime/public/cpp/rulebased/test_data/deva_phone_enter b/chromeos/services/ime/public/cpp/rulebased/test_data/deva_phone_enter
new file mode 100644
index 0000000..7b49ca4
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/test_data/deva_phone_enter
@@ -0,0 +1,14 @@
+# Created from RulebasedImeTest.DevaPhone_Enter
+engine_id: DEVA_PHONE
+key_events {
+  code: KEY_N
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: ENTER
+  shift: false
+  altgr: false
+  caps_lock: false
+}
diff --git a/chromeos/services/ime/public/cpp/rulebased/test_data/deva_phone_transforms b/chromeos/services/ime/public/cpp/rulebased/test_data/deva_phone_transforms
new file mode 100644
index 0000000..e8c610f8
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/test_data/deva_phone_transforms
@@ -0,0 +1,20 @@
+# Created from RulebasedImeTest.Transforms_deva_phone
+engine_id: DEVA_PHONE
+key_events {
+  code: PERIOD
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: PERIOD
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: DIGIT0
+  shift: true
+  altgr: false
+  caps_lock: false
+}
diff --git a/chromeos/services/ime/public/cpp/rulebased/test_data/persian b/chromeos/services/ime/public/cpp/rulebased/test_data/persian
new file mode 100644
index 0000000..1c2ddce
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/test_data/persian
@@ -0,0 +1,20 @@
+# Created from RulebasedImeTest.Persian
+engine_id: FA
+key_events {
+  code: KEY_A
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: KEY_V
+  shift: true
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: SPACE
+  shift: true
+  altgr: false
+  caps_lock: false
+}
diff --git a/chromeos/services/ime/public/cpp/rulebased/test_data/thai b/chromeos/services/ime/public/cpp/rulebased/test_data/thai
new file mode 100644
index 0000000..2f6c6db
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/test_data/thai
@@ -0,0 +1,14 @@
+# Created from RulebasedImeTest.Thai
+engine_id: TH
+key_events {
+  code: KEY_A
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: KEY_A
+  shift: false
+  altgr: true
+  caps_lock: false
+}
diff --git a/chromeos/services/ime/public/cpp/rulebased/test_data/thai_pattajoti b/chromeos/services/ime/public/cpp/rulebased/test_data/thai_pattajoti
new file mode 100644
index 0000000..bdb8c5fc
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/test_data/thai_pattajoti
@@ -0,0 +1,14 @@
+# Created from RulebasedImeTest.Thai
+engine_id: TH_PATTAJOTI
+key_events {
+  code: KEY_A
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: KEY_B
+  shift: true
+  altgr: false
+  caps_lock: false
+}
diff --git a/chromeos/services/ime/public/cpp/rulebased/test_data/thai_tis b/chromeos/services/ime/public/cpp/rulebased/test_data/thai_tis
new file mode 100644
index 0000000..2800078a
--- /dev/null
+++ b/chromeos/services/ime/public/cpp/rulebased/test_data/thai_tis
@@ -0,0 +1,14 @@
+# Created from RulebasedImeTest.Thai
+engine_id: TH_TIS
+key_events {
+  code: KEY_A
+  shift: false
+  altgr: false
+  caps_lock: false
+}
+key_events {
+  code: KEY_M
+  shift: true
+  altgr: false
+  caps_lock: false
+}
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index 877419e..5a6915c2 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -1768,6 +1768,7 @@
   form->unique_renderer_id = form_element.UniqueRendererFormId();
   form->url = GetCanonicalOriginForDocument(frame->GetDocument());
   form->action = GetCanonicalActionForForm(form_element);
+  form->is_action_empty = form_element.Action().IsNull();
   if (IsAutofillFieldMetadataEnabled()) {
     SCOPED_UMA_HISTOGRAM_TIMER(
         "PasswordManager.ButtonTitlePerformance.HasFormTag");
diff --git a/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
index a0a8c93..433bfc8 100644
--- a/components/autofill/content/renderer/form_autofill_util_browsertest.cc
+++ b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -21,18 +21,23 @@
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/blink/public/web/web_select_element.h"
 
-using autofill::FormFieldData;
 using autofill::mojom::ButtonTitleType;
 using blink::WebDocument;
 using blink::WebElement;
+using blink::WebElementCollection;
 using blink::WebFormControlElement;
 using blink::WebFormElement;
 using blink::WebInputElement;
 using blink::WebLocalFrame;
+using blink::WebNode;
 using blink::WebSelectElement;
 using blink::WebString;
 using blink::WebVector;
 
+namespace autofill {
+namespace form_util {
+namespace {
+
 struct AutofillFieldLabelSourceCase {
   const char* html;
   const FormFieldData::LabelSource label_source;
@@ -160,7 +165,7 @@
     WebElement target = web_frame->GetDocument().GetElementById("target");
     ASSERT_FALSE(target.IsNull());
     EXPECT_EQ(base::UTF8ToUTF16(test_case.expected_label),
-              autofill::form_util::FindChildText(target));
+              FindChildText(target));
   }
 }
 
@@ -177,14 +182,13 @@
     ASSERT_FALSE(target.IsNull());
     WebVector<WebElement> web_to_skip =
         web_frame->GetDocument().QuerySelectorAll("div[class='skip']");
-    std::set<blink::WebNode> to_skip;
+    std::set<WebNode> to_skip;
     for (size_t i = 0; i < web_to_skip.size(); ++i) {
       to_skip.insert(web_to_skip[i]);
     }
 
     EXPECT_EQ(base::UTF8ToUTF16(test_case.expected_label),
-              autofill::form_util::FindChildTextWithIgnoreListForTesting(
-                  target, to_skip));
+              FindChildTextWithIgnoreListForTesting(target, to_skip));
   }
 }
 
@@ -213,8 +217,8 @@
     FormFieldData::LabelSource label_source =
         FormFieldData::LabelSource::kUnknown;
     base::string16 label;
-    autofill::form_util::InferLabelForElementForTesting(form_target, stop_words,
-                                                        &label, &label_source);
+    InferLabelForElementForTesting(form_target, stop_words, &label,
+                                   &label_source);
     EXPECT_EQ(base::UTF8ToUTF16(test_case.expected_label), label);
   }
 }
@@ -290,8 +294,7 @@
   const WebFormElement& form_target = target.ToConst<WebFormElement>();
   ASSERT_FALSE(form_target.IsNull());
 
-  autofill::ButtonTitleList actual =
-      autofill::form_util::InferButtonTitlesForTesting(form_target);
+  autofill::ButtonTitleList actual = InferButtonTitlesForTesting(form_target);
   autofill::ButtonTitleList expected = {
       {base::UTF8ToUTF16("Clear field"),
        ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE},
@@ -327,8 +330,7 @@
   const WebFormElement& form_target = target.ToConst<WebFormElement>();
   ASSERT_FALSE(form_target.IsNull());
 
-  autofill::ButtonTitleList actual =
-      autofill::form_util::InferButtonTitlesForTesting(form_target);
+  autofill::ButtonTitleList actual = InferButtonTitlesForTesting(form_target);
 
   int total_length = 0;
   for (auto title : actual) {
@@ -358,8 +360,7 @@
   const WebElement& body = web_frame->GetDocument().Body();
   ASSERT_FALSE(body.IsNull());
 
-  autofill::ButtonTitleList actual =
-      autofill::form_util::InferButtonTitlesForTesting(body);
+  autofill::ButtonTitleList actual = InferButtonTitlesForTesting(body);
   autofill::ButtonTitleList expected = {
       {base::UTF8ToUTF16("Show password"),
        ButtonTitleType::INPUT_ELEMENT_BUTTON_TYPE},
@@ -377,23 +378,22 @@
       "<input type='password' id='name3'>"
       "<input type='text' id='name4' disabled>");
 
-  const std::vector<blink::WebElement> dummy_fieldsets;
+  const std::vector<WebElement> dummy_fieldsets;
 
   WebLocalFrame* web_frame = GetMainFrame();
   ASSERT_TRUE(web_frame);
-  std::vector<blink::WebFormControlElement> control_elements;
-  blink::WebElementCollection inputs =
+  std::vector<WebFormControlElement> control_elements;
+  WebElementCollection inputs =
       web_frame->GetDocument().GetElementsByHTMLTagName("input");
-  for (blink::WebElement element = inputs.FirstItem(); !element.IsNull();
+  for (WebElement element = inputs.FirstItem(); !element.IsNull();
        element = inputs.NextItem()) {
-    control_elements.push_back(element.To<blink::WebFormControlElement>());
+    control_elements.push_back(element.To<WebFormControlElement>());
   }
 
   autofill::FormData target;
-  EXPECT_TRUE(
-      autofill::form_util::UnownedPasswordFormElementsAndFieldSetsToFormData(
-          dummy_fieldsets, control_elements, nullptr, web_frame->GetDocument(),
-          nullptr, autofill::form_util::EXTRACT_NONE, &target, nullptr));
+  EXPECT_TRUE(UnownedPasswordFormElementsAndFieldSetsToFormData(
+      dummy_fieldsets, control_elements, nullptr, web_frame->GetDocument(),
+      nullptr, EXTRACT_NONE, &target, nullptr));
   const struct {
     const char* const name;
     bool enabled;
@@ -416,23 +416,22 @@
       "<input type='password' id='name3'>"
       "<input type='text' id='name4' readonly>");
 
-  const std::vector<blink::WebElement> dummy_fieldsets;
+  const std::vector<WebElement> dummy_fieldsets;
 
   WebLocalFrame* web_frame = GetMainFrame();
   ASSERT_TRUE(web_frame);
-  std::vector<blink::WebFormControlElement> control_elements;
-  blink::WebElementCollection inputs =
+  std::vector<WebFormControlElement> control_elements;
+  WebElementCollection inputs =
       web_frame->GetDocument().GetElementsByHTMLTagName("input");
-  for (blink::WebElement element = inputs.FirstItem(); !element.IsNull();
+  for (WebElement element = inputs.FirstItem(); !element.IsNull();
        element = inputs.NextItem()) {
-    control_elements.push_back(element.To<blink::WebFormControlElement>());
+    control_elements.push_back(element.To<WebFormControlElement>());
   }
 
   autofill::FormData target;
-  EXPECT_TRUE(
-      autofill::form_util::UnownedPasswordFormElementsAndFieldSetsToFormData(
-          dummy_fieldsets, control_elements, nullptr, web_frame->GetDocument(),
-          nullptr, autofill::form_util::EXTRACT_NONE, &target, nullptr));
+  EXPECT_TRUE(UnownedPasswordFormElementsAndFieldSetsToFormData(
+      dummy_fieldsets, control_elements, nullptr, web_frame->GetDocument(),
+      nullptr, EXTRACT_NONE, &target, nullptr));
   const struct {
     const char* const name;
     bool readonly;
@@ -453,27 +452,26 @@
       "<input type='text' id='name1' value='123'>"
       "<input type='text' id='name2' style='display:none'>");
 
-  const std::vector<blink::WebElement> dummy_fieldsets;
+  const std::vector<WebElement> dummy_fieldsets;
 
   WebLocalFrame* web_frame = GetMainFrame();
   ASSERT_TRUE(web_frame);
 
-  std::vector<blink::WebFormControlElement> control_elements;
+  std::vector<WebFormControlElement> control_elements;
   control_elements.push_back(web_frame->GetDocument()
                                  .GetElementById("name1")
-                                 .To<blink::WebFormControlElement>());
+                                 .To<WebFormControlElement>());
   control_elements.push_back(web_frame->GetDocument()
                                  .GetElementById("name2")
-                                 .To<blink::WebFormControlElement>());
+                                 .To<WebFormControlElement>());
 
   EXPECT_TRUE(autofill::form_util::IsWebElementVisible(control_elements[0]));
   EXPECT_FALSE(autofill::form_util::IsWebElementVisible(control_elements[1]));
 
   autofill::FormData target;
-  EXPECT_TRUE(
-      autofill::form_util::UnownedPasswordFormElementsAndFieldSetsToFormData(
-          dummy_fieldsets, control_elements, nullptr, web_frame->GetDocument(),
-          nullptr, autofill::form_util::EXTRACT_NONE, &target, nullptr));
+  EXPECT_TRUE(UnownedPasswordFormElementsAndFieldSetsToFormData(
+      dummy_fieldsets, control_elements, nullptr, web_frame->GetDocument(),
+      nullptr, EXTRACT_NONE, &target, nullptr));
   ASSERT_EQ(2u, target.fields.size());
   EXPECT_EQ(base::UTF8ToUTF16("name1"), target.fields[0].name);
   EXPECT_TRUE(target.fields[0].is_focusable);
@@ -484,19 +482,17 @@
 TEST_F(FormAutofillUtilsTest, FindFormByUniqueId) {
   LoadHTML("<body><form id='form1'></form><form id='form2'></form></body>");
   WebDocument doc = GetMainFrame()->GetDocument();
-  blink::WebVector<WebFormElement> forms;
+  WebVector<WebFormElement> forms;
   doc.Forms(forms);
 
   for (const auto& form : forms) {
-    EXPECT_EQ(form, autofill::form_util::FindFormByUniqueRendererId(
-                        doc, form.UniqueRendererFormId()));
+    EXPECT_EQ(form,
+              FindFormByUniqueRendererId(doc, form.UniqueRendererFormId()));
   }
 
   // Expect null form element for non-existing form id.
   uint32_t non_existing_id = forms[0].UniqueRendererFormId() + 1000;
-  EXPECT_TRUE(
-      autofill::form_util::FindFormByUniqueRendererId(doc, non_existing_id)
-          .IsNull());
+  EXPECT_TRUE(FindFormByUniqueRendererId(doc, non_existing_id).IsNull());
 }
 
 TEST_F(FormAutofillUtilsTest, FindFormControlByUniqueId) {
@@ -506,7 +502,6 @@
   auto input1 = doc.GetElementById("i1").To<WebInputElement>();
   auto input2 = doc.GetElementById("i2").To<WebInputElement>();
   uint32_t non_existing_id = input2.UniqueRendererFormControlId() + 1000;
-  using autofill::form_util::FindFormControlElementsByUniqueRendererId;
 
   EXPECT_EQ(input1, FindFormControlElementsByUniqueRendererId(
                         doc, input1.UniqueRendererFormControlId()));
@@ -527,9 +522,7 @@
                                         non_existing_id,
                                         input1.UniqueRendererFormControlId()};
 
-  auto elements =
-      autofill::form_util::FindFormControlElementsByUniqueRendererId(
-          doc, renderer_ids);
+  auto elements = FindFormControlElementsByUniqueRendererId(doc, renderer_ids);
 
   ASSERT_EQ(3u, elements.size());
   EXPECT_EQ(input3, elements[0]);
@@ -551,9 +544,8 @@
                                         non_existing_id,
                                         input1.UniqueRendererFormControlId()};
 
-  auto elements =
-      autofill::form_util::FindFormControlElementsByUniqueRendererId(
-          doc, form.UniqueRendererFormId(), renderer_ids);
+  auto elements = FindFormControlElementsByUniqueRendererId(
+      doc, form.UniqueRendererFormId(), renderer_ids);
 
   // |input3| is not in the form, so it shouldn't be returned.
   ASSERT_EQ(3u, elements.size());
@@ -563,7 +555,7 @@
 
   // Expect that no elements are retured for non existing form id.
   uint32_t non_existing_form_id = form.UniqueRendererFormId() + 1000;
-  elements = autofill::form_util::FindFormControlElementsByUniqueRendererId(
+  elements = FindFormControlElementsByUniqueRendererId(
       doc, non_existing_form_id, renderer_ids);
   ASSERT_EQ(3u, elements.size());
   EXPECT_TRUE(elements[0].IsNull());
@@ -713,10 +705,41 @@
   auto input = doc.GetElementById("input1").To<WebFormControlElement>();
   uint32_t input_id = input.UniqueRendererFormControlId();
 
-  EXPECT_TRUE(
-      autofill::form_util::IsFormControlVisible(GetMainFrame(), input_id));
+  EXPECT_TRUE(IsFormControlVisible(GetMainFrame(), input_id));
 
   // Hide a field.
   input.SetAttribute("style", "display:none");
   EXPECT_FALSE(autofill::form_util::IsFormVisible(GetMainFrame(), input_id));
 }
+
+TEST_F(FormAutofillUtilsTest, IsActionEmptyFalse) {
+  LoadHTML(
+      "<body><form id='form1' action='done.html'><input "
+      "id='i1'></form></body>");
+  WebDocument doc = GetMainFrame()->GetDocument();
+  auto web_form = doc.GetElementById("form1").To<WebFormElement>();
+
+  FormData form_data;
+  ASSERT_TRUE(WebFormElementToFormData(
+      web_form, WebFormControlElement(), nullptr /*field_data_manager*/,
+      EXTRACT_VALUE, &form_data, nullptr /* FormFieldData */));
+
+  EXPECT_FALSE(form_data.is_action_empty);
+}
+
+TEST_F(FormAutofillUtilsTest, IsActionEmptyTrue) {
+  LoadHTML("<body><form id='form1'><input id='i1'></form></body>");
+  WebDocument doc = GetMainFrame()->GetDocument();
+  auto web_form = doc.GetElementById("form1").To<WebFormElement>();
+
+  FormData form_data;
+  ASSERT_TRUE(WebFormElementToFormData(
+      web_form, WebFormControlElement(), nullptr /*field_data_manager*/,
+      EXTRACT_VALUE, &form_data, nullptr /* FormFieldData */));
+
+  EXPECT_TRUE(form_data.is_action_empty);
+}
+
+}  // namespace
+}  // namespace form_util
+}  // namespace autofill
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index 23091d0..731f598 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -784,20 +784,33 @@
   if (touch_to_fill_state_ != TouchToFillState::kShouldShow)
     return false;
 
-  const WebInputElement* element = ToWebInputElement(&control_element);
+  const WebInputElement* input_element = ToWebInputElement(&control_element);
   WebInputElement username_element;
   WebInputElement password_element;
   PasswordInfo* password_info = nullptr;
-  if (!element ||
-      !FindPasswordInfoForElement(*element, &username_element,
+  if (!input_element ||
+      !FindPasswordInfoForElement(*input_element, &username_element,
                                   &password_element, &password_info)) {
     return false;
   }
 
-  DCHECK(!password_element.IsNull());
-  if (!IsElementEditable(password_element))
+  // Don't trigger Touch To Fill when there is no password element or it is not
+  // editable.
+  if (password_element.IsNull() || !IsElementEditable(password_element))
     return false;
 
+  // Highlight the fields that are about to be filled by the user and remember
+  // the old autofill state of |username_element| and |password_element|.
+  if (IsUsernameAmendable(username_element,
+                          input_element->IsPasswordFieldForAutofill())) {
+    username_autofill_state_ = username_element.GetAutofillState();
+    username_element.SetAutofillState(WebAutofillState::kPreviewed);
+  }
+
+  password_autofill_state_ = password_element.GetAutofillState();
+  password_element.SetAutofillState(WebAutofillState::kPreviewed);
+
+  focused_input_element_ = *input_element;
   GetPasswordManagerDriver()->ShowTouchToFill();
   touch_to_fill_state_ = TouchToFillState::kIsShowing;
   return true;
@@ -1208,6 +1221,24 @@
 
 void PasswordAutofillAgent::TouchToFillDismissed() {
   touch_to_fill_state_ = TouchToFillState::kWasShown;
+
+  // Clear the autofill state from the username and password element. Note that
+  // we don't make use of ClearPreview() here, since this is considering the
+  // elements' SuggestedValue(), which Touch To Fill does not set.
+  DCHECK(!focused_input_element_.IsNull());
+  WebInputElement username_element;
+  WebInputElement password_element;
+  PasswordInfo* password_info = nullptr;
+  if (!FindPasswordInfoForElement(focused_input_element_, &username_element,
+                                  &password_element, &password_info)) {
+    return;
+  }
+
+  if (!username_element.IsNull())
+    username_element.SetAutofillState(username_autofill_state_);
+
+  if (!password_element.IsNull())
+    password_element.SetAutofillState(password_autofill_state_);
 }
 
 void PasswordAutofillAgent::AnnotateFieldsWithParsingResult(
diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc
index 7516f93f..727f5b9 100644
--- a/components/autofill/core/browser/autofill_test_utils.cc
+++ b/components/autofill/core/browser/autofill_test_utils.cc
@@ -120,6 +120,7 @@
                      mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
   form->url = GURL("http://myform.com/form.html");
   form->action = GURL("http://myform.com/submit.html");
+  form->is_action_empty = true;
   form->main_frame_origin =
       url::Origin::Create(GURL("https://myform_root.com/form.html"));
   types->clear();
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_client.cc
index 87afdd5..1cfb0274 100644
--- a/components/autofill/core/browser/payments/payments_client.cc
+++ b/components/autofill/core/browser/payments/payments_client.cc
@@ -1313,7 +1313,7 @@
 
   identity::ScopeSet payments_scopes;
   payments_scopes.insert(kPaymentsOAuth2Scope);
-  std::string account_id =
+  CoreAccountId account_id =
       account_info_getter_->GetAccountInfoForPaymentsServer().account_id;
   if (invalidate_old) {
     DCHECK(!access_token_.empty());
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 1a24880..74d9cf8 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -1313,7 +1313,7 @@
     // seeing them in the dropdown.
     if (!prefs::IsUserOptedInWalletSyncTransport(
             pref_service_,
-            sync_service_->GetAuthenticatedAccountInfo().account_id)) {
+            sync_service_->GetAuthenticatedAccountInfo().account_id.id)) {
       return false;
     }
   }
@@ -1839,7 +1839,8 @@
       features::kAutofillEnableAccountWalletStorage));
 
   bool is_opted_in = prefs::IsUserOptedInWalletSyncTransport(
-      pref_service_, sync_service_->GetAuthenticatedAccountInfo().account_id);
+      pref_service_,
+      sync_service_->GetAuthenticatedAccountInfo().account_id.id);
 
   AutofillMetrics::LogWalletSyncTransportCardsOptIn(is_opted_in);
 
@@ -1851,7 +1852,7 @@
   DCHECK_EQ(AutofillSyncSigninState::kSignedInAndWalletSyncTransportEnabled,
             GetSyncSigninState());
   prefs::SetUserOptedInWalletSyncTransport(
-      pref_service_, sync_service_->GetAuthenticatedAccountInfo().account_id,
+      pref_service_, sync_service_->GetAuthenticatedAccountInfo().account_id.id,
       /*opted_in=*/true);
 }
 
@@ -1908,7 +1909,8 @@
   if (GetSyncSigninState() ==
       AutofillSyncSigninState::kSignedInAndWalletSyncTransportEnabled) {
     prefs::SetUserOptedInWalletSyncTransport(
-        pref_service_, sync_service_->GetAuthenticatedAccountInfo().account_id,
+        pref_service_,
+        sync_service_->GetAuthenticatedAccountInfo().account_id.id,
         /*opted_in=*/true);
   }
 }
diff --git a/components/autofill/core/common/form_data.cc b/components/autofill/core/common/form_data.cc
index 8f7ab442..e69ae3a 100644
--- a/components/autofill/core/common/form_data.cc
+++ b/components/autofill/core/common/form_data.cc
@@ -98,10 +98,12 @@
 bool FormData::SimilarFormAs(const FormData& form) const {
   if (name != form.name || id_attribute != form.id_attribute ||
       name_attribute != form.name_attribute || url != form.url ||
-      action != form.action || is_form_tag != form.is_form_tag ||
+      action != form.action || is_action_empty != form.is_action_empty ||
+      is_form_tag != form.is_form_tag ||
       is_formless_checkout != form.is_formless_checkout ||
-      fields.size() != form.fields.size())
+      fields.size() != form.fields.size()) {
     return false;
+  }
   for (size_t i = 0; i < fields.size(); ++i) {
     if (!fields[i].SimilarFieldAs(form.fields[i]))
       return false;
@@ -124,7 +126,7 @@
 bool FormData::operator==(const FormData& form) const {
   return name == form.name && id_attribute == form.id_attribute &&
          name_attribute == form.name_attribute && url == form.url &&
-         action == form.action &&
+         action == form.action && is_action_empty == form.is_action_empty &&
          unique_renderer_id == form.unique_renderer_id &&
          submission_event == form.submission_event &&
          is_form_tag == form.is_form_tag &&
@@ -237,6 +239,7 @@
   buffer << Tr{} << "Unique renderer Id:" << form.unique_renderer_id;
   buffer << Tr{} << "URL:" << form.url;
   buffer << Tr{} << "Action:" << form.action;
+  buffer << Tr{} << "Is action empty:" << form.is_action_empty;
   buffer << Tr{} << "Is <form> tag:" << form.is_form_tag;
   for (size_t i = 0; i < form.fields.size(); ++i) {
     buffer << Tag{"tr"};
diff --git a/components/autofill/core/common/form_data.h b/components/autofill/core/common/form_data.h
index a30f4555..932394b 100644
--- a/components/autofill/core/common/form_data.h
+++ b/components/autofill/core/common/form_data.h
@@ -78,6 +78,10 @@
   GURL url;
   // The action target of the form.
   GURL action;
+  // If the form in the DOM has an empty action attribute, the |action| field in
+  // the FormData is set to the frame URL of the embedding document. This field
+  // indicates whether the action attribute is empty in the form in the DOM.
+  bool is_action_empty = false;
   // The URL of main frame containing this form.
   url::Origin main_frame_origin;
   // True if this form is a form tag.
diff --git a/components/autofill/core/common/mojom/autofill_types.mojom b/components/autofill/core/common/mojom/autofill_types.mojom
index aececd0..716bc5f 100644
--- a/components/autofill/core/common/mojom/autofill_types.mojom
+++ b/components/autofill/core/common/mojom/autofill_types.mojom
@@ -153,6 +153,7 @@
   array<ButtonTitleInfo> button_titles;
   url.mojom.Url url;
   url.mojom.Url action;
+  bool is_action_empty;
   url.mojom.Origin main_frame_origin;
   bool is_form_tag;
   bool is_formless_checkout;
diff --git a/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc b/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
index ff970d4..117da5b 100644
--- a/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
+++ b/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
@@ -107,6 +107,7 @@
     return false;
   if (!data.ReadAction(&out->action))
     return false;
+  out->is_action_empty = data.is_action_empty();
   if (!data.ReadMainFrameOrigin(&out->main_frame_origin))
     return false;
 
diff --git a/components/autofill/core/common/mojom/autofill_types_mojom_traits.h b/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
index 804c2913..a4acca8 100644
--- a/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
+++ b/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
@@ -196,6 +196,10 @@
 
   static const GURL& action(const autofill::FormData& r) { return r.action; }
 
+  static bool is_action_empty(const autofill::FormData& r) {
+    return r.is_action_empty;
+  }
+
   static const url::Origin& main_frame_origin(const autofill::FormData& r) {
     return r.main_frame_origin;
   }
diff --git a/components/consent_auditor/DEPS b/components/consent_auditor/DEPS
index c6d9382..ead2691e 100644
--- a/components/consent_auditor/DEPS
+++ b/components/consent_auditor/DEPS
@@ -3,4 +3,5 @@
   "+components/prefs",
   "+components/sync",
   "+components/variations",
+  "+google_apis/gaia",
 ]
diff --git a/components/consent_auditor/consent_auditor.h b/components/consent_auditor/consent_auditor.h
index ff46df2..8914fa7 100644
--- a/components/consent_auditor/consent_auditor.h
+++ b/components/consent_auditor/consent_auditor.h
@@ -14,6 +14,7 @@
 #include "base/memory/weak_ptr.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/sync/model/model_type_sync_bridge.h"
+#include "google_apis/gaia/core_account_id.h"
 
 namespace consent_auditor {
 
@@ -51,33 +52,33 @@
   // Records the ARC Play |consent| for the signed-in GAIA account with the ID
   // |account_id| (as defined in AccountInfo).
   virtual void RecordArcPlayConsent(
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       const sync_pb::UserConsentTypes::ArcPlayTermsOfServiceConsent&
           consent) = 0;
 
   // Records the ARC Google Location Service |consent| for the signed-in GAIA
   // account with the ID |account_id| (as defined in AccountInfo).
   virtual void RecordArcGoogleLocationServiceConsent(
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       const sync_pb::UserConsentTypes::ArcGoogleLocationServiceConsent&
           consent) = 0;
 
   // Records the ARC Backup and Restore |consent| for the signed-in GAIA
   // account with the ID |account_id| (as defined in AccountInfo).
   virtual void RecordArcBackupAndRestoreConsent(
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       const sync_pb::UserConsentTypes::ArcBackupAndRestoreConsent& consent) = 0;
 
   // Records the Sync |consent| for the signed-in GAIA account with the ID
   // |account_id| (as defined in AccountInfo).
   virtual void RecordSyncConsent(
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       const sync_pb::UserConsentTypes::SyncConsent& consent) = 0;
 
   // Records the Assistant activity control |consent| for the signed-in GAIA
   // account with the ID |accounts_id| (as defined in Account Info).
   virtual void RecordAssistantActivityControlConsent(
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       const sync_pb::UserConsentTypes::AssistantActivityControlConsent&
           consent) = 0;
 
diff --git a/components/consent_auditor/consent_auditor_impl.cc b/components/consent_auditor/consent_auditor_impl.cc
index 455d433..80d2b9a 100644
--- a/components/consent_auditor/consent_auditor_impl.cc
+++ b/components/consent_auditor/consent_auditor_impl.cc
@@ -29,12 +29,12 @@
 const char kLocalConsentLocaleKey[] = "locale";
 
 std::unique_ptr<sync_pb::UserConsentSpecifics> CreateUserConsentSpecifics(
-    const std::string& account_id,
+    const CoreAccountId& account_id,
     const std::string& locale,
     base::Clock* clock) {
   std::unique_ptr<sync_pb::UserConsentSpecifics> specifics =
       std::make_unique<sync_pb::UserConsentSpecifics>();
-  specifics->set_account_id(account_id);
+  specifics->set_account_id(account_id.id);
   specifics->set_client_consent_time_usec(
       clock->Now().since_origin().InMicroseconds());
   specifics->set_locale(locale);
@@ -69,7 +69,7 @@
 }
 
 void ConsentAuditorImpl::RecordArcPlayConsent(
-    const std::string& account_id,
+    const CoreAccountId& account_id,
     const ArcPlayTermsOfServiceConsent& consent) {
   std::unique_ptr<sync_pb::UserConsentSpecifics> specifics =
       CreateUserConsentSpecifics(account_id, app_locale_, clock_);
@@ -81,7 +81,7 @@
 }
 
 void ConsentAuditorImpl::RecordArcGoogleLocationServiceConsent(
-    const std::string& account_id,
+    const CoreAccountId& account_id,
     const UserConsentTypes::ArcGoogleLocationServiceConsent& consent) {
   std::unique_ptr<sync_pb::UserConsentSpecifics> specifics =
       CreateUserConsentSpecifics(account_id, app_locale_, clock_);
@@ -94,7 +94,7 @@
 }
 
 void ConsentAuditorImpl::RecordArcBackupAndRestoreConsent(
-    const std::string& account_id,
+    const CoreAccountId& account_id,
     const UserConsentTypes::ArcBackupAndRestoreConsent& consent) {
   std::unique_ptr<sync_pb::UserConsentSpecifics> specifics =
       CreateUserConsentSpecifics(account_id, app_locale_, clock_);
@@ -107,7 +107,7 @@
 }
 
 void ConsentAuditorImpl::RecordSyncConsent(
-    const std::string& account_id,
+    const CoreAccountId& account_id,
     const UserConsentTypes::SyncConsent& consent) {
   std::unique_ptr<sync_pb::UserConsentSpecifics> specifics =
       CreateUserConsentSpecifics(account_id, app_locale_, clock_);
@@ -119,7 +119,7 @@
 }
 
 void ConsentAuditorImpl::RecordAssistantActivityControlConsent(
-    const std::string& account_id,
+    const CoreAccountId& account_id,
     const sync_pb::UserConsentTypes::AssistantActivityControlConsent& consent) {
   std::unique_ptr<sync_pb::UserConsentSpecifics> specifics =
       CreateUserConsentSpecifics(account_id, app_locale_, clock_);
diff --git a/components/consent_auditor/consent_auditor_impl.h b/components/consent_auditor/consent_auditor_impl.h
index 57bb5d44..f8a66f8 100644
--- a/components/consent_auditor/consent_auditor_impl.h
+++ b/components/consent_auditor/consent_auditor_impl.h
@@ -42,22 +42,22 @@
   static void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
   void RecordArcPlayConsent(
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       const sync_pb::UserConsentTypes::ArcPlayTermsOfServiceConsent& consent)
       override;
   void RecordArcGoogleLocationServiceConsent(
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       const sync_pb::UserConsentTypes::ArcGoogleLocationServiceConsent& consent)
       override;
   void RecordArcBackupAndRestoreConsent(
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       const sync_pb::UserConsentTypes::ArcBackupAndRestoreConsent& consent)
       override;
   void RecordSyncConsent(
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       const sync_pb::UserConsentTypes::SyncConsent& consent) override;
   void RecordAssistantActivityControlConsent(
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       const sync_pb::UserConsentTypes::AssistantActivityControlConsent& consent)
       override;
   void RecordLocalConsent(const std::string& feature,
@@ -68,7 +68,7 @@
 
  private:
   std::unique_ptr<sync_pb::UserConsentSpecifics> ConstructUserConsentSpecifics(
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       Feature feature,
       const std::vector<int>& description_grd_ids,
       int confirmation_grd_id,
diff --git a/components/consent_auditor/fake_consent_auditor.cc b/components/consent_auditor/fake_consent_auditor.cc
index 4543bfc4..62c9779 100644
--- a/components/consent_auditor/fake_consent_auditor.cc
+++ b/components/consent_auditor/fake_consent_auditor.cc
@@ -32,7 +32,7 @@
 FakeConsentAuditor::~FakeConsentAuditor() {}
 
 void FakeConsentAuditor::RecordSyncConsent(
-    const std::string& account_id,
+    const CoreAccountId& account_id,
     const sync_pb::UserConsentTypes::SyncConsent& consent) {
   // TODO(markusheintz): Change the Fake to store the proto instead of calling
   // RecordGaiaConsent.
@@ -44,13 +44,13 @@
 }
 
 void FakeConsentAuditor::RecordAssistantActivityControlConsent(
-    const std::string& account_id,
+    const CoreAccountId& account_id,
     const sync_pb::UserConsentTypes::AssistantActivityControlConsent& consent) {
   NOTIMPLEMENTED();
 }
 
 void FakeConsentAuditor::RecordGaiaConsent(
-    const std::string& account_id,
+    const CoreAccountId& account_id,
     consent_auditor::Feature feature,
     const std::vector<int>& description_grd_ids,
     int confirmation_grd_id,
diff --git a/components/consent_auditor/fake_consent_auditor.h b/components/consent_auditor/fake_consent_auditor.h
index 8a00db1..45bffeb 100644
--- a/components/consent_auditor/fake_consent_auditor.h
+++ b/components/consent_auditor/fake_consent_auditor.h
@@ -23,22 +23,22 @@
 
   // ConsentAuditor implementation.
   void RecordSyncConsent(
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       const sync_pb::UserConsentTypes::SyncConsent& consent) override;
   MOCK_METHOD2(
       RecordArcPlayConsent,
-      void(const std::string&,
+      void(const CoreAccountId&,
            const sync_pb::UserConsentTypes::ArcPlayTermsOfServiceConsent&));
   MOCK_METHOD2(
       RecordArcBackupAndRestoreConsent,
-      void(const std::string&,
+      void(const CoreAccountId&,
            const sync_pb::UserConsentTypes::ArcBackupAndRestoreConsent&));
   MOCK_METHOD2(
       RecordArcGoogleLocationServiceConsent,
-      void(const std::string&,
+      void(const CoreAccountId&,
            const sync_pb::UserConsentTypes::ArcGoogleLocationServiceConsent&));
   void RecordAssistantActivityControlConsent(
-      const std::string& account_id,
+      const CoreAccountId& account_id,
       const sync_pb::UserConsentTypes::AssistantActivityControlConsent& consent)
       override;
 
@@ -50,13 +50,13 @@
 
   // Methods for fake.
   // TODO(markusheintz): Replace the usage of this methods in all tests.
-  void RecordGaiaConsent(const std::string& account_id,
+  void RecordGaiaConsent(const CoreAccountId& account_id,
                          consent_auditor::Feature feature,
                          const std::vector<int>& description_grd_ids,
                          int confirmation_grd_id,
                          consent_auditor::ConsentStatus status);
 
-  const std::string& account_id() const { return account_id_; }
+  const CoreAccountId& account_id() const { return account_id_; }
 
   const sync_pb::UserConsentTypes::SyncConsent& recorded_sync_consent() const {
     return recorded_sync_consent_;
@@ -82,7 +82,7 @@
   }
 
  private:
-  std::string account_id_;
+  CoreAccountId account_id_;
 
   sync_pb::UserConsentTypes::SyncConsent recorded_sync_consent_;
   sync_pb::UserConsentTypes_ArcPlayTermsOfServiceConsent recorded_play_consent_;
diff --git a/components/feed/core/feed_networking_host.cc b/components/feed/core/feed_networking_host.cc
index 3fd9a1db..2c729793 100644
--- a/components/feed/core/feed_networking_host.cc
+++ b/components/feed/core/feed_networking_host.cc
@@ -255,7 +255,7 @@
 
     if (status_code == net::HTTP_UNAUTHORIZED) {
       identity::ScopeSet scopes{kAuthenticationScope};
-      std::string account_id = identity_manager_->GetPrimaryAccountId();
+      CoreAccountId account_id = identity_manager_->GetPrimaryAccountId();
       identity_manager_->RemoveAccessTokenFromCache(account_id, scopes,
                                                     access_token_);
     }
diff --git a/components/invalidation/impl/deprecated_invalidator_registrar_unittest.cc b/components/invalidation/impl/deprecated_invalidator_registrar_unittest.cc
index e7a0f3a..35365e7 100644
--- a/components/invalidation/impl/deprecated_invalidator_registrar_unittest.cc
+++ b/components/invalidation/impl/deprecated_invalidator_registrar_unittest.cc
@@ -51,7 +51,7 @@
     return registrar_.GetInvalidatorState();
   }
 
-  void UpdateCredentials(const std::string& email,
+  void UpdateCredentials(const CoreAccountId& account_id,
                          const std::string& token) override {
     // Do nothing.
   }
diff --git a/components/invalidation/impl/fake_invalidator.cc b/components/invalidation/impl/fake_invalidator.cc
index a46de12..83be636 100644
--- a/components/invalidation/impl/fake_invalidator.cc
+++ b/components/invalidation/impl/fake_invalidator.cc
@@ -21,8 +21,8 @@
   return registrar_.GetRegisteredIds(handler);
 }
 
-const std::string& FakeInvalidator::GetCredentialsEmail() const {
-  return email_;
+const CoreAccountId& FakeInvalidator::GetCredentialsAccountId() const {
+  return account_id_;
 }
 
 const std::string& FakeInvalidator::GetCredentialsToken() const {
@@ -60,9 +60,9 @@
   return registrar_.GetInvalidatorState();
 }
 
-void FakeInvalidator::UpdateCredentials(
-    const std::string& email, const std::string& token) {
-  email_ = email;
+void FakeInvalidator::UpdateCredentials(const CoreAccountId& account_id,
+                                        const std::string& token) {
+  account_id_ = account_id;
   token_ = token;
 }
 
diff --git a/components/invalidation/impl/fake_invalidator.h b/components/invalidation/impl/fake_invalidator.h
index 2a868d9..0a41f912 100644
--- a/components/invalidation/impl/fake_invalidator.h
+++ b/components/invalidation/impl/fake_invalidator.h
@@ -23,7 +23,7 @@
   bool IsHandlerRegistered(InvalidationHandler* handler) const;
   ObjectIdSet GetRegisteredIds(InvalidationHandler* handler) const;
   const std::string& GetUniqueId() const;
-  const std::string& GetCredentialsEmail() const;
+  const CoreAccountId& GetCredentialsAccountId() const;
   const std::string& GetCredentialsToken() const;
 
   void EmitOnInvalidatorStateChange(InvalidatorState state);
@@ -37,7 +37,7 @@
                            const Topics& topics) override;
   void UnregisterHandler(InvalidationHandler* handler) override;
   InvalidatorState GetInvalidatorState() const override;
-  void UpdateCredentials(const std::string& email,
+  void UpdateCredentials(const CoreAccountId& account_id,
                          const std::string& token) override;
   void RequestDetailedStatus(base::Callback<void(const base::DictionaryValue&)>
                                  callback) const override;
@@ -45,7 +45,7 @@
  private:
   DeprecatedInvalidatorRegistrar registrar_;
   std::string state_;
-  std::string email_;
+  CoreAccountId account_id_;
   std::string token_;
 };
 
diff --git a/components/invalidation/impl/fcm_invalidation_service.cc b/components/invalidation/impl/fcm_invalidation_service.cc
index ad585392..9b4c80c6 100644
--- a/components/invalidation/impl/fcm_invalidation_service.cc
+++ b/components/invalidation/impl/fcm_invalidation_service.cc
@@ -204,7 +204,7 @@
 
 void FCMInvalidationService::OnActiveAccountLogout() {
   diagnostic_info_.active_account_logged_out = base::Time::Now();
-  diagnostic_info_.active_account_id = std::string();
+  diagnostic_info_.active_account_id = CoreAccountId();
   if (IsStarted()) {
     StopInvalidator();
     if (!client_id_.empty())
@@ -370,7 +370,8 @@
   status.SetBoolean(
       "InvalidationService.Ready-to-start-on-active-account-login",
       was_ready_to_start_on_login);
-  status.SetString("InvalidationService.Active-account-id", active_account_id);
+  status.SetString("InvalidationService.Active-account-id",
+                   active_account_id.id);
   return status;
 }
 
diff --git a/components/invalidation/impl/fcm_invalidation_service.h b/components/invalidation/impl/fcm_invalidation_service.h
index 5866942d..db5a907 100644
--- a/components/invalidation/impl/fcm_invalidation_service.h
+++ b/components/invalidation/impl/fcm_invalidation_service.h
@@ -110,7 +110,7 @@
     base::Time service_was_started;
     bool was_already_started_on_login = false;
     bool was_ready_to_start_on_login = false;
-    std::string active_account_id;
+    CoreAccountId active_account_id;
   };
 
   bool IsReadyToStart();
diff --git a/components/invalidation/impl/gcm_network_channel.cc b/components/invalidation/impl/gcm_network_channel.cc
index c9be980..af61bde 100644
--- a/components/invalidation/impl/gcm_network_channel.cc
+++ b/components/invalidation/impl/gcm_network_channel.cc
@@ -434,7 +434,7 @@
   callback.Run(*diagnostic_info_.CollectDebugData());
 }
 
-void GCMNetworkChannel::UpdateCredentials(const std::string& email,
+void GCMNetworkChannel::UpdateCredentials(const CoreAccountId& account_id,
                                           const std::string& token) {
   // Do nothing. We get access token by requesting it for every message.
 }
diff --git a/components/invalidation/impl/gcm_network_channel.h b/components/invalidation/impl/gcm_network_channel.h
index 04bfa4fd..c126f46 100644
--- a/components/invalidation/impl/gcm_network_channel.h
+++ b/components/invalidation/impl/gcm_network_channel.h
@@ -67,7 +67,7 @@
       invalidation::MessageCallback* incoming_receiver) override;
 
   // SyncNetworkChannel implementation.
-  void UpdateCredentials(const std::string& email,
+  void UpdateCredentials(const CoreAccountId& account_id,
                          const std::string& token) override;
   int GetInvalidationClientType() override;
   void RequestDetailedStatus(
diff --git a/components/invalidation/impl/invalidation_notifier.cc b/components/invalidation/impl/invalidation_notifier.cc
index cde5616..559f232 100644
--- a/components/invalidation/impl/invalidation_notifier.cc
+++ b/components/invalidation/impl/invalidation_notifier.cc
@@ -63,8 +63,8 @@
   return registrar_.GetInvalidatorState();
 }
 
-void InvalidationNotifier::UpdateCredentials(
-    const std::string& email, const std::string& token) {
+void InvalidationNotifier::UpdateCredentials(const CoreAccountId& account_id,
+                                             const std::string& token) {
   if (state_ == STOPPED) {
     invalidation_listener_.Start(
         base::Bind(&invalidation::CreateInvalidationClient),
@@ -77,7 +77,7 @@
         this);
     state_ = STARTED;
   }
-  invalidation_listener_.UpdateCredentials(email, token);
+  invalidation_listener_.UpdateCredentials(account_id, token);
 }
 
 void InvalidationNotifier::RequestDetailedStatus(
diff --git a/components/invalidation/impl/invalidation_notifier.h b/components/invalidation/impl/invalidation_notifier.h
index 88ebb9f6..b5bfd6a3 100644
--- a/components/invalidation/impl/invalidation_notifier.h
+++ b/components/invalidation/impl/invalidation_notifier.h
@@ -54,7 +54,7 @@
                            const ObjectIdSet& ids) override;
   void UnregisterHandler(InvalidationHandler* handler) override;
   InvalidatorState GetInvalidatorState() const override;
-  void UpdateCredentials(const std::string& email,
+  void UpdateCredentials(const CoreAccountId& account_id,
                          const std::string& token) override;
   void RequestDetailedStatus(base::Callback<void(const base::DictionaryValue&)>
                                  callback) const override;
diff --git a/components/invalidation/impl/invalidator.h b/components/invalidation/impl/invalidator.h
index 04af8055..95186be 100644
--- a/components/invalidation/impl/invalidator.h
+++ b/components/invalidation/impl/invalidator.h
@@ -15,6 +15,7 @@
 #include "components/invalidation/public/invalidation_export.h"
 #include "components/invalidation/public/invalidation_util.h"
 #include "components/invalidation/public/invalidator_state.h"
+#include "google_apis/gaia/core_account_id.h"
 
 namespace syncer {
 class InvalidationHandler;
@@ -83,8 +84,8 @@
   // The observers won't be notified of any notifications until
   // UpdateCredentials is called at least once. It can be called more than
   // once.
-  virtual void UpdateCredentials(
-      const std::string& email, const std::string& token) = 0;
+  virtual void UpdateCredentials(const CoreAccountId& account_id,
+                                 const std::string& token) = 0;
 
   // Requests internal detailed status to be posted back to the callback.
   virtual void RequestDetailedStatus(
diff --git a/components/invalidation/impl/invalidator_registrar_unittest.cc b/components/invalidation/impl/invalidator_registrar_unittest.cc
index 4a8541a..0dd5c28 100644
--- a/components/invalidation/impl/invalidator_registrar_unittest.cc
+++ b/components/invalidation/impl/invalidator_registrar_unittest.cc
@@ -54,7 +54,7 @@
     return registrar_.GetInvalidatorState();
   }
 
-  void UpdateCredentials(const std::string& email,
+  void UpdateCredentials(const CoreAccountId& account_id,
                          const std::string& token) override {
     // Do nothing.
   }
diff --git a/components/invalidation/impl/invalidator_test_template.h b/components/invalidation/impl/invalidator_test_template.h
index 16f4093..47bdc08 100644
--- a/components/invalidation/impl/invalidator_test_template.h
+++ b/components/invalidation/impl/invalidator_test_template.h
@@ -106,7 +106,7 @@
     Invalidator* const invalidator = this->delegate_.GetInvalidator();
 
     this->delegate_.WaitForInvalidator();
-    invalidator->UpdateCredentials("foo@bar.com", "fake_token");
+    invalidator->UpdateCredentials(CoreAccountId("foo@bar.com"), "fake_token");
     this->delegate_.WaitForInvalidator();
 
     return invalidator;
diff --git a/components/invalidation/impl/non_blocking_invalidator.cc b/components/invalidation/impl/non_blocking_invalidator.cc
index af4e5fe..6ee03cb 100644
--- a/components/invalidation/impl/non_blocking_invalidator.cc
+++ b/components/invalidation/impl/non_blocking_invalidator.cc
@@ -114,7 +114,8 @@
       const NonBlockingInvalidator::InitializeOptions& initialize_options);
   void Teardown();
   void UpdateRegisteredIds(const ObjectIdSet& ids);
-  void UpdateCredentials(const std::string& email, const std::string& token);
+  void UpdateCredentials(const CoreAccountId& account_id,
+                         const std::string& token);
   void RequestDetailedStatus(
       base::Callback<void(const base::DictionaryValue&)> callback) const;
 
@@ -182,10 +183,11 @@
   invalidation_notifier_->UpdateRegisteredIds(this, ids);
 }
 
-void NonBlockingInvalidator::Core::UpdateCredentials(const std::string& email,
-                                                     const std::string& token) {
+void NonBlockingInvalidator::Core::UpdateCredentials(
+    const CoreAccountId& account_id,
+    const std::string& token) {
   DCHECK(network_task_runner_->BelongsToCurrentThread());
-  invalidation_notifier_->UpdateCredentials(email, token);
+  invalidation_notifier_->UpdateCredentials(account_id, token);
 }
 
 void NonBlockingInvalidator::Core::RequestDetailedStatus(
@@ -282,13 +284,13 @@
   return registrar_.GetInvalidatorState();
 }
 
-void NonBlockingInvalidator::UpdateCredentials(const std::string& email,
+void NonBlockingInvalidator::UpdateCredentials(const CoreAccountId& account_id,
                                                const std::string& token) {
   DCHECK(parent_task_runner_->BelongsToCurrentThread());
   if (!network_task_runner_->PostTask(
           FROM_HERE,
           base::BindOnce(&NonBlockingInvalidator::Core::UpdateCredentials,
-                         core_, email, token))) {
+                         core_, account_id, token))) {
     NOTREACHED();
   }
 }
diff --git a/components/invalidation/impl/non_blocking_invalidator.h b/components/invalidation/impl/non_blocking_invalidator.h
index 3cad930d..a8ec2cc 100644
--- a/components/invalidation/impl/non_blocking_invalidator.h
+++ b/components/invalidation/impl/non_blocking_invalidator.h
@@ -64,7 +64,7 @@
                            const ObjectIdSet& ids) override;
   void UnregisterHandler(InvalidationHandler* handler) override;
   InvalidatorState GetInvalidatorState() const override;
-  void UpdateCredentials(const std::string& email,
+  void UpdateCredentials(const CoreAccountId& account_id,
                          const std::string& token) override;
   void RequestDetailedStatus(base::Callback<void(const base::DictionaryValue&)>
                                  callback) const override;
diff --git a/components/invalidation/impl/push_client_channel.cc b/components/invalidation/impl/push_client_channel.cc
index 709d8e5..6bebebfdd 100644
--- a/components/invalidation/impl/push_client_channel.cc
+++ b/components/invalidation/impl/push_client_channel.cc
@@ -41,8 +41,8 @@
   push_client_->RemoveObserver(this);
 }
 
-void PushClientChannel::UpdateCredentials(
-    const std::string& email, const std::string& token) {
+void PushClientChannel::UpdateCredentials(const CoreAccountId& account_id,
+                                          const std::string& token) {
   net::NetworkTrafficAnnotationTag traffic_annotation =
       net::DefineNetworkTrafficAnnotation("puch_client_channel", R"(
         semantics {
@@ -77,7 +77,9 @@
           }
         }
     )");
-  push_client_->UpdateCredentials(email, token, traffic_annotation);
+  // TODO(https://crbug.com/1010544): Possibly pass an account id instead of
+  // string here.
+  push_client_->UpdateCredentials(account_id.id, token, traffic_annotation);
 }
 
 int PushClientChannel::GetInvalidationClientType() {
diff --git a/components/invalidation/impl/push_client_channel.h b/components/invalidation/impl/push_client_channel.h
index 70a6359..fb6ee09a7 100644
--- a/components/invalidation/impl/push_client_channel.h
+++ b/components/invalidation/impl/push_client_channel.h
@@ -43,7 +43,7 @@
   // If not connected, connects with the given credentials.  If
   // already connected, the next connection attempt will use the given
   // credentials.
-  void UpdateCredentials(const std::string& email,
+  void UpdateCredentials(const CoreAccountId& account_id,
                          const std::string& token) override;
   int GetInvalidationClientType() override;
 
diff --git a/components/invalidation/impl/push_client_channel_unittest.cc b/components/invalidation/impl/push_client_channel_unittest.cc
index b8a580b1..98f9ddb 100644
--- a/components/invalidation/impl/push_client_channel_unittest.cc
+++ b/components/invalidation/impl/push_client_channel_unittest.cc
@@ -67,12 +67,13 @@
 // Call UpdateCredentials on the channel.  It should propagate it to
 // the push client.
 TEST_F(PushClientChannelTest, UpdateCredentials) {
-  const char kEmail[] = "foo@bar.com";
+  const CoreAccountId kAccountId("foo@bar.com");
   const char kToken[] = "token";
   EXPECT_TRUE(fake_push_client_->email().empty());
   EXPECT_TRUE(fake_push_client_->token().empty());
-  push_client_channel_.UpdateCredentials(kEmail, kToken);
-  EXPECT_EQ(kEmail, fake_push_client_->email());
+  // PushClient treats account IDs as emails. See https://crbug.com/1010544
+  push_client_channel_.UpdateCredentials(kAccountId, kToken);
+  EXPECT_EQ(kAccountId.id, fake_push_client_->email());
   EXPECT_EQ(kToken, fake_push_client_->token());
 }
 
diff --git a/components/invalidation/impl/sync_invalidation_listener.cc b/components/invalidation/impl/sync_invalidation_listener.cc
index 6954ad7..506bec6 100644
--- a/components/invalidation/impl/sync_invalidation_listener.cc
+++ b/components/invalidation/impl/sync_invalidation_listener.cc
@@ -94,9 +94,10 @@
 }
 
 void SyncInvalidationListener::UpdateCredentials(
-    const std::string& email, const std::string& token) {
+    const CoreAccountId& account_id,
+    const std::string& token) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  sync_network_channel_->UpdateCredentials(email, token);
+  sync_network_channel_->UpdateCredentials(account_id, token);
 }
 
 void SyncInvalidationListener::UpdateRegisteredIds(const ObjectIdSet& ids) {
diff --git a/components/invalidation/impl/sync_invalidation_listener.h b/components/invalidation/impl/sync_invalidation_listener.h
index 7505c4f..cb0b1547 100644
--- a/components/invalidation/impl/sync_invalidation_listener.h
+++ b/components/invalidation/impl/sync_invalidation_listener.h
@@ -75,7 +75,8 @@
           invalidation_state_tracker_task_runner,
       Delegate* delegate);
 
-  void UpdateCredentials(const std::string& email, const std::string& token);
+  void UpdateCredentials(const CoreAccountId& account_id,
+                         const std::string& token);
 
   // Update the set of object IDs that we're interested in getting
   // notifications for.  May be called at any time.
diff --git a/components/invalidation/impl/sync_system_resources.h b/components/invalidation/impl/sync_system_resources.h
index 5f49061..f9870b5 100644
--- a/components/invalidation/impl/sync_system_resources.h
+++ b/components/invalidation/impl/sync_system_resources.h
@@ -23,6 +23,7 @@
 #include "components/invalidation/public/invalidation_export.h"
 #include "components/invalidation/public/invalidator_state.h"
 #include "google/cacheinvalidation/include/system-resources.h"
+#include "google_apis/gaia/core_account_id.h"
 #include "jingle/notifier/base/notifier_options.h"
 
 namespace network {
@@ -119,8 +120,8 @@
 
   // Subclass should implement UpdateCredentials to pass new token to channel
   // library.
-  virtual void UpdateCredentials(const std::string& email,
-      const std::string& token) = 0;
+  virtual void UpdateCredentials(const CoreAccountId& account_id,
+                                 const std::string& token) = 0;
 
   // Return value from GetInvalidationClientType will be passed to
   // invalidation::CreateInvalidationClient. Subclass should return one of the
diff --git a/components/invalidation/impl/sync_system_resources_unittest.cc b/components/invalidation/impl/sync_system_resources_unittest.cc
index 632c6dc..c77a8dc 100644
--- a/components/invalidation/impl/sync_system_resources_unittest.cc
+++ b/components/invalidation/impl/sync_system_resources_unittest.cc
@@ -188,7 +188,7 @@
 
   void SendMessage(const std::string& message) override {}
 
-  void UpdateCredentials(const std::string& email,
+  void UpdateCredentials(const CoreAccountId& account_id,
                          const std::string& token) override {}
 
   int GetInvalidationClientType() override { return 0; }
diff --git a/components/invalidation/impl/ticl_invalidation_service.cc b/components/invalidation/impl/ticl_invalidation_service.cc
index dd065d66..8614121 100644
--- a/components/invalidation/impl/ticl_invalidation_service.cc
+++ b/components/invalidation/impl/ticl_invalidation_service.cc
@@ -386,12 +386,12 @@
 }
 
 void TiclInvalidationService::UpdateInvalidatorCredentials() {
-  std::string email = identity_provider_->GetActiveAccountId();
+  CoreAccountId account_id = identity_provider_->GetActiveAccountId();
 
-  DCHECK(!email.empty()) << "Expected user to be signed in.";
+  DCHECK(!account_id.empty()) << "Expected user to be signed in.";
 
-  DVLOG(2) << "UpdateCredentials: " << email;
-  invalidator_->UpdateCredentials(email, access_token_);
+  DVLOG(2) << "UpdateCredentials: " << account_id;
+  invalidator_->UpdateCredentials(account_id, access_token_);
 }
 
 void TiclInvalidationService::StopInvalidator() {
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
index 3a3916a..f35d3f4 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
@@ -391,7 +391,7 @@
 
   if (fetch_result == FetchResult::HTTP_ERROR_UNAUTHORIZED) {
     identity::ScopeSet scopes{kContentSuggestionsApiScope};
-    std::string account_id = identity_manager_->GetPrimaryAccountId();
+    CoreAccountId account_id = identity_manager_->GetPrimaryAccountId();
     identity_manager_->RemoveAccessTokenFromCache(account_id, scopes,
                                                   access_token);
   }
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
index aa9b1991..938dd68 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -776,6 +776,10 @@
       return false;
   }
 
+  // TODO(crbug.com/1014174): Ignore back-forward cached navigations for now.
+  if (navigation_handle->IsServedFromBackForwardCache())
+    return false;
+
   return true;
 }
 
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
index ee9c2f8..33f2cea 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
@@ -10,17 +10,20 @@
 #include "base/memory/weak_ptr.h"
 #include "base/process/kill.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
 #include "base/timer/mock_timer.h"
 #include "components/page_load_metrics/browser/page_load_metrics_test_content_browser_client.h"
 #include "components/page_load_metrics/browser/page_load_tracker.h"
 #include "components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/resource_load_info.mojom.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/web_contents_tester.h"
 #include "net/base/net_errors.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using content::NavigationSimulator;
@@ -1475,4 +1478,50 @@
   MetricsWebContentsObserver::RecordFeatureUsage(main_rfh(), features);
 }
 
+class MetricsWebContentsObserverBackForwardCacheTest
+    : public MetricsWebContentsObserverTest {
+ public:
+  MetricsWebContentsObserverBackForwardCacheTest() {
+    feature_list_.InitWithFeaturesAndParameters(
+        {{features::kBackForwardCache,
+          {{"TimeToLiveInBackForwardCacheInSeconds", "3600"}}}},
+        {});
+  }
+
+  ~MetricsWebContentsObserverBackForwardCacheTest() override {}
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(MetricsWebContentsObserverBackForwardCacheTest,
+       RecordFeatureUsageWithBackForwardCache) {
+  content::WebContentsTester* web_contents_tester =
+      content::WebContentsTester::For(web_contents());
+  web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
+  ASSERT_EQ(main_rfh()->GetLastCommittedURL().spec(), GURL(kDefaultTestUrl));
+
+  std::vector<blink::mojom::WebFeature> web_features1{
+      blink::mojom::WebFeature::kHTMLMarqueeElement};
+  mojom::PageLoadFeatures features1(web_features1, {}, {});
+  MetricsWebContentsObserver::RecordFeatureUsage(main_rfh(), features1);
+
+  web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
+  content::NavigationSimulator::GoBack(web_contents());
+
+  std::vector<blink::mojom::WebFeature> web_features2{
+      blink::mojom::WebFeature::kFormAttribute};
+  mojom::PageLoadFeatures features2(web_features2, {}, {});
+  MetricsWebContentsObserver::RecordFeatureUsage(main_rfh(), features2);
+
+  std::vector<std::vector<blink::mojom::WebFeature>> features;
+  for (const auto& observation : observed_features()) {
+    features.push_back(observation.features);
+  }
+
+  // For now back-forward cached navigations are not tracked and the events
+  // after the history navigation are not tracked.
+  EXPECT_THAT(features, testing::ElementsAre(web_features1));
+}
+
 }  // namespace page_load_metrics
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index 26d7d39..9d3887c 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -145,14 +145,6 @@
   return false;
 }
 
-std::map<base::string16, const PasswordForm*> ByUsername(
-    const std::vector<const PasswordForm*> forms) {
-  std::map<base::string16, const PasswordForm*> by_username;
-  for (const auto* form : forms)
-    by_username[form->username_value] = form;
-  return by_username;
-}
-
 }  // namespace
 
 PasswordFormManager::PasswordFormManager(
@@ -324,8 +316,7 @@
     SanitizePossibleUsernames(&pending_credentials_);
     pending_credentials_.date_created = base::Time::Now();
     votes_uploader_.SendVotesOnSave(observed_form_, *parsed_submitted_form_,
-                                    ByUsername(GetBestMatches()),
-                                    &pending_credentials_);
+                                    GetBestMatches(), &pending_credentials_);
     SavePendingToStore(false /*update*/);
   } else {
     ProcessUpdate();
@@ -904,7 +895,7 @@
 
   // Calculate the user's action based on existing matches and the submitted
   // form.
-  metrics_recorder_->CalculateUserAction(ByUsername(GetBestMatches()),
+  metrics_recorder_->CalculateUserAction(GetBestMatches(),
                                          *parsed_submitted_form_);
 
   // This function might be called multiple times so set variables that are
@@ -1055,9 +1046,8 @@
   }
 
   if (pending_credentials_.times_used == 1) {
-    votes_uploader_.UploadFirstLoginVotes(ByUsername(GetBestMatches()),
-                                          pending_credentials_,
-                                          *parsed_submitted_form_);
+    votes_uploader_.UploadFirstLoginVotes(
+        GetBestMatches(), pending_credentials_, *parsed_submitted_form_);
   }
 }
 
diff --git a/components/password_manager/core/browser/password_form_metrics_recorder.cc b/components/password_manager/core/browser/password_form_metrics_recorder.cc
index 76e2c45..bed04d5 100644
--- a/components/password_manager/core/browser/password_form_metrics_recorder.cc
+++ b/components/password_manager/core/browser/password_form_metrics_recorder.cc
@@ -15,6 +15,7 @@
 #include "components/password_manager/core/browser/form_fetcher.h"
 #include "components/password_manager/core/browser/password_bubble_experiment.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
 #include "components/password_manager/core/browser/statistics_table.h"
 
 using autofill::FieldPropertiesFlags;
@@ -295,8 +296,8 @@
 }
 
 void PasswordFormMetricsRecorder::CalculateUserAction(
-    const std::map<base::string16, const autofill::PasswordForm*>& best_matches,
-    const autofill::PasswordForm& submitted_form) {
+    const std::vector<const PasswordForm*>& best_matches,
+    const PasswordForm& submitted_form) {
   const base::string16& submitted_password =
       !submitted_form.new_password_value.empty()
           ? submitted_form.new_password_value
@@ -306,8 +307,8 @@
     // In case the submitted form does not have a username field we do not
     // autofill. Thus the user either explicitly chose this credential from the
     // dropdown, or created a new password.
-    for (const auto& match : best_matches) {
-      if (match.second->password_value == submitted_password) {
+    for (const PasswordForm* match : best_matches) {
+      if (match->password_value == submitted_password) {
         user_action_ = UserAction::kChoose;
         return;
       }
@@ -320,14 +321,15 @@
   // In case the submitted form has a username value, check if there is an
   // existing match with the same username. If not, the user created a new
   // credential.
-  auto found = best_matches.find(submitted_form.username_value);
-  if (found == best_matches.end()) {
+  const PasswordForm* existing_match =
+      password_manager_util::FindFormByUsername(best_matches,
+                                                submitted_form.username_value);
+  if (!existing_match) {
     user_action_ = UserAction::kOverrideUsernameAndPassword;
     return;
   }
 
   // Otherwise check if the user changed the password.
-  const autofill::PasswordForm* existing_match = found->second;
   if (existing_match->password_value != submitted_password) {
     user_action_ = UserAction::kOverridePassword;
     return;
diff --git a/components/password_manager/core/browser/password_form_metrics_recorder.h b/components/password_manager/core/browser/password_form_metrics_recorder.h
index dc7f09b5a..2923e60 100644
--- a/components/password_manager/core/browser/password_form_metrics_recorder.h
+++ b/components/password_manager/core/browser/password_form_metrics_recorder.h
@@ -312,8 +312,7 @@
   // matches. Also inspects |manager_action_| to correctly detect if the
   // user chose a credential.
   void CalculateUserAction(
-      const std::map<base::string16, const autofill::PasswordForm*>&
-          best_matches,
+      const std::vector<const autofill::PasswordForm*>& best_matches,
       const autofill::PasswordForm& submitted_form);
 
   // Allow tests to explicitly set a value for |user_action_|.
diff --git a/components/password_manager/core/browser/password_manager_util.cc b/components/password_manager/core/browser/password_manager_util.cc
index 586de4c..6c5dba4 100644
--- a/components/password_manager/core/browser/password_manager_util.cc
+++ b/components/password_manager/core/browser/password_manager_util.cc
@@ -60,18 +60,6 @@
          std::make_pair(!rhs->is_public_suffix_match, rhs->date_last_used);
 }
 
-// Returns a form with the given |username_value| from |credentials|, or nullptr
-// if none exists.
-const PasswordForm* FindByUsername(
-    const std::vector<const PasswordForm*>& credentials,
-    const base::string16& username_value) {
-  for (const auto* form : credentials) {
-    if (form->username_value == username_value)
-      return form;
-  }
-  return nullptr;
-}
-
 }  // namespace
 
 // Update |credential| to reflect usage.
@@ -271,6 +259,16 @@
   *preferred_match = *non_federated_same_scheme->begin();
 }
 
+const PasswordForm* FindFormByUsername(
+    const std::vector<const PasswordForm*>& forms,
+    const base::string16& username_value) {
+  for (const PasswordForm* form : forms) {
+    if (form->username_value == username_value)
+      return form;
+  }
+  return nullptr;
+}
+
 const PasswordForm* GetMatchForUpdating(
     const PasswordForm& submitted_form,
     const std::vector<const PasswordForm*>& credentials) {
@@ -282,7 +280,7 @@
 
   // Try to return form with matching |username_value|.
   const PasswordForm* username_match =
-      FindByUsername(credentials, submitted_form.username_value);
+      FindFormByUsername(credentials, submitted_form.username_value);
   if (username_match) {
     if (!username_match->is_public_suffix_match)
       return username_match;
diff --git a/components/password_manager/core/browser/password_manager_util.h b/components/password_manager/core/browser/password_manager_util.h
index 2512b944..4473085 100644
--- a/components/password_manager/core/browser/password_manager_util.h
+++ b/components/password_manager/core/browser/password_manager_util.h
@@ -115,6 +115,12 @@
     std::vector<const autofill::PasswordForm*>* best_matches,
     const autofill::PasswordForm** preferred_match);
 
+// Returns a form with the given |username_value| from |forms|, or nullptr if
+// none exists. If multiple matches exist, returns the first one.
+const autofill::PasswordForm* FindFormByUsername(
+    const std::vector<const autofill::PasswordForm*>& forms,
+    const base::string16& username_value);
+
 // If the user submits a form, they may have used existing credentials, new
 // credentials, or modified existing credentials that should be updated.
 // The function returns a form from |credentials| that is the best candidate to
diff --git a/components/password_manager/core/browser/votes_uploader.cc b/components/password_manager/core/browser/votes_uploader.cc
index 7f7158fb..15f8d35 100644
--- a/components/password_manager/core/browser/votes_uploader.cc
+++ b/components/password_manager/core/browser/votes_uploader.cc
@@ -34,6 +34,7 @@
 using autofill::ServerFieldType;
 using autofill::ServerFieldTypeSet;
 using autofill::ValueElementPair;
+using password_manager_util::FindFormByUsername;
 
 using Logger = autofill::SavePasswordProgressLogger;
 using StringID = autofill::SavePasswordProgressLogger::StringID;
@@ -119,11 +120,12 @@
 // which doesn't have a username.
 bool IsAddingUsernameToExistingMatch(
     const PasswordForm& credentials,
-    const std::map<base::string16, const PasswordForm*>& matches) {
-  const auto match = matches.find(base::string16());
-  return !credentials.username_value.empty() && match != matches.end() &&
-         !match->second->is_public_suffix_match &&
-         match->second->password_value == credentials.password_value;
+    const std::vector<const PasswordForm*>& matches) {
+  if (credentials.username_value.empty())
+    return false;
+  const PasswordForm* match = FindFormByUsername(matches, base::string16());
+  return match && !match->is_public_suffix_match &&
+         match->password_value == credentials.password_value;
 }
 
 // Helper functions for character type classification. The built-in functions
@@ -180,7 +182,7 @@
 void VotesUploader::SendVotesOnSave(
     const FormData& observed,
     const PasswordForm& submitted_form,
-    const std::map<base::string16, const PasswordForm*>& best_matches,
+    const std::vector<const PasswordForm*>& best_matches,
     PasswordForm* pending_credentials) {
   if (pending_credentials->times_used == 1 ||
       IsAddingUsernameToExistingMatch(*pending_credentials, best_matches)) {
@@ -366,7 +368,7 @@
 
 // TODO(crbug.com/840384): Share common code with UploadPasswordVote.
 void VotesUploader::UploadFirstLoginVotes(
-    const std::map<base::string16, const PasswordForm*>& best_matches,
+    const std::vector<const PasswordForm*>& best_matches,
     const PasswordForm& pending_credentials,
     const PasswordForm& form_to_upload) {
   AutofillDownloadManager* download_manager =
@@ -485,19 +487,20 @@
 
 void VotesUploader::SetKnownValueFlag(
     const PasswordForm& pending_credentials,
-    const std::map<base::string16, const PasswordForm*>& best_matches,
+    const std::vector<const PasswordForm*>& best_matches,
     FormStructure* form) {
   const base::string16& known_username = pending_credentials.username_value;
   base::string16 known_password;
   if (password_overridden_) {
     // If we are updating a password, the known value should be the old
     // password, not the new one.
-    auto it = best_matches.find(known_username);
-    if (it == best_matches.end()) {
+    const PasswordForm* match =
+        FindFormByUsername(best_matches, known_username);
+    if (!match) {
       // Username was not found, do nothing.
       return;
     }
-    known_password = it->second->password_value;
+    known_password = match->password_value;
   } else {
     known_password = pending_credentials.password_value;
   }
diff --git a/components/password_manager/core/browser/votes_uploader.h b/components/password_manager/core/browser/votes_uploader.h
index c699846..b0ab27fd 100644
--- a/components/password_manager/core/browser/votes_uploader.h
+++ b/components/password_manager/core/browser/votes_uploader.h
@@ -42,8 +42,7 @@
   void SendVotesOnSave(
       const autofill::FormData& observed,
       const autofill::PasswordForm& submitted_form,
-      const std::map<base::string16, const autofill::PasswordForm*>&
-          best_matches,
+      const std::vector<const autofill::PasswordForm*>& best_matches,
       autofill::PasswordForm* pending_credentials);
 
   // Check to see if |pending| corresponds to an account creation form. If we
@@ -65,8 +64,7 @@
   // Sends USERNAME and PASSWORD votes, when a credential is used to login for
   // the first time. |form_to_upload| is the submitted login form.
   void UploadFirstLoginVotes(
-      const std::map<base::string16, const autofill::PasswordForm*>&
-          best_matches,
+      const std::vector<const autofill::PasswordForm*>& best_matches,
       const autofill::PasswordForm& pending_credentials,
       const autofill::PasswordForm& form_to_upload);
 
@@ -150,8 +148,7 @@
   // contained a previously stored credential on submission.
   void SetKnownValueFlag(
       const autofill::PasswordForm& pending_credentials,
-      const std::map<base::string16, const autofill::PasswordForm*>&
-          best_matches,
+      const std::vector<const autofill::PasswordForm*>& best_matches,
       autofill::FormStructure* form_to_upload);
 
   // Searches for |username| in |all_possible_usernames| of |match|. If the
diff --git a/components/pdf/renderer/pdf_accessibility_tree.cc b/components/pdf/renderer/pdf_accessibility_tree.cc
index 292fa04..a5e9aaa 100644
--- a/components/pdf/renderer/pdf_accessibility_tree.cc
+++ b/components/pdf/renderer/pdf_accessibility_tree.cc
@@ -208,13 +208,9 @@
 
 }  // namespace
 
-PdfAccessibilityTree::PdfAccessibilityTree(
-    content::RendererPpapiHost* host,
-    PP_Instance instance)
-    : host_(host),
-      instance_(instance),
-      zoom_(1.0) {
-}
+PdfAccessibilityTree::PdfAccessibilityTree(content::RendererPpapiHost* host,
+                                           PP_Instance instance)
+    : host_(host), instance_(instance) {}
 
 PdfAccessibilityTree::~PdfAccessibilityTree() {
   content::RenderAccessibility* render_accessibility = GetRenderAccessibility();
@@ -265,12 +261,12 @@
 
 void PdfAccessibilityTree::SetAccessibilityViewportInfo(
     const PP_PrivateAccessibilityViewportInfo& viewport_info) {
-  zoom_ = viewport_info.zoom;
-  CHECK_GT(zoom_, 0);
+  zoom_device_scale_factor_ = viewport_info.zoom_device_scale_factor;
+  CHECK_GT(zoom_device_scale_factor_, 0);
   scroll_ = ToVector2dF(viewport_info.scroll);
-  scroll_.Scale(1.0 / zoom_);
+  scroll_.Scale(1.0 / zoom_device_scale_factor_);
   offset_ = ToVector2dF(viewport_info.offset);
-  offset_.Scale(1.0 / zoom_);
+  offset_.Scale(1.0 / zoom_device_scale_factor_);
 
   selection_start_page_index_ = viewport_info.selection_start_page_index;
   selection_start_char_index_ = viewport_info.selection_start_char_index;
@@ -830,7 +826,7 @@
 
 gfx::Transform* PdfAccessibilityTree::MakeTransformFromViewInfo() {
   gfx::Transform* transform = new gfx::Transform();
-  float scale_factor = zoom_ / GetDeviceScaleFactor();
+  float scale_factor = zoom_device_scale_factor_ / GetDeviceScaleFactor();
   transform->Scale(scale_factor, scale_factor);
   transform->Translate(offset_);
   transform->Translate(-scroll_);
diff --git a/components/pdf/renderer/pdf_accessibility_tree.h b/components/pdf/renderer/pdf_accessibility_tree.h
index 0d4b2dd..331cdbc 100644
--- a/components/pdf/renderer/pdf_accessibility_tree.h
+++ b/components/pdf/renderer/pdf_accessibility_tree.h
@@ -164,7 +164,7 @@
   ui::AXTree tree_;
   content::RendererPpapiHost* host_;
   PP_Instance instance_;
-  double zoom_;
+  double zoom_device_scale_factor_ = 1.0;
   gfx::Vector2dF scroll_;
   gfx::Vector2dF offset_;
   uint32_t selection_start_page_index_ = 0;
diff --git a/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc b/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
index 174c2719..7c0bf64 100644
--- a/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
+++ b/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
@@ -157,7 +157,7 @@
     ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
         pak_file, ui::SCALE_FACTOR_NONE);
 
-    viewport_info_.zoom = 1.0;
+    viewport_info_.zoom_device_scale_factor = 1.0;
     viewport_info_.scroll = {0, 0};
     viewport_info_.offset = {0, 0};
     viewport_info_.selection_start_page_index = 0;
diff --git a/components/policy/proto/BUILD.gn b/components/policy/proto/BUILD.gn
index 66358133..70f90c23 100644
--- a/components/policy/proto/BUILD.gn
+++ b/components/policy/proto/BUILD.gn
@@ -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("//third_party/libprotobuf-mutator/fuzzable_proto_library.gni")
 import("//third_party/protobuf/proto_library.gni")
 
 # The proto files need to be a component to avoid duplicate symbols the way the
@@ -54,3 +55,14 @@
   component_build_force_source_set = true
   defines = [ "POLICY_PROTO_COMPILATION" ]
 }
+
+if (use_libfuzzer) {
+  fuzzable_proto_library("chrome_device_policy_full_runtime_proto") {
+    proto_out_dir = "components/policy/proto/fuzzer"
+
+    sources = [
+      "chrome_device_policy.proto",
+      "policy_common_definitions.proto",
+    ]
+  }
+}
diff --git a/components/policy/tools/generate_policy_source.py b/components/policy/tools/generate_policy_source.py
index 4a5a0b3..5a21d3d 100755
--- a/components/policy/tools/generate_policy_source.py
+++ b/components/policy/tools/generate_policy_source.py
@@ -20,9 +20,13 @@
 import re
 import sys
 import textwrap
-import types
 from xml.sax.saxutils import escape as xml_escape
 
+if sys.version_info.major == 2:
+  string_type = basestring
+else:
+  string_type = str
+
 CHROME_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Google\\\\Chrome'
 CHROMIUM_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Chromium'
 
@@ -193,7 +197,7 @@
                            'in policy_templates.json)!')
       policies_already_in_group.add(policy)
       if not policy in available_policies:
-        raise RuntimeError('Invalid policy:' + policy + ' in atomic group ' +
+        raise RuntimeError('Invalid policy: ' + policy + ' in atomic group ' +
                            self.name + '.\n')
 
 
@@ -355,7 +359,7 @@
   risk_tags.ComputeMaxTags(policy_details)
   sorted_policy_details = sorted(policy_details, key=lambda policy: policy.name)
 
-  policy_details_set = map((lambda x: x.name), policy_details)
+  policy_details_set = list(map((lambda x: x.name), policy_details))
   policies_already_in_group = set()
   policy_atomic_groups = [
       PolicyAtomicGroup(group, policy_details_set, policies_already_in_group)
@@ -658,8 +662,8 @@
 
   def IsConsecutiveInterval(self, seq):
     sortedSeq = sorted(seq)
-    return all(sortedSeq[i] + 1 == sortedSeq[i + 1]
-               for i in xrange(len(sortedSeq) - 1))
+    return all(
+        sortedSeq[i] + 1 == sortedSeq[i + 1] for i in range(len(sortedSeq) - 1))
 
   def GetEnumIntegerType(self, schema, is_sensitive_value, name):
     assert all(type(x) == int for x in schema['enum'])
@@ -737,7 +741,7 @@
     if '$ref' in schema:
       if 'id' in schema:
         raise RuntimeError("Schemas with a $ref can't have an id")
-      if not isinstance(schema['$ref'], types.StringTypes):
+      if not isinstance(schema['$ref'], string_type):
         raise RuntimeError("$ref attribute must be a string")
       return schema['$ref']
 
@@ -921,7 +925,7 @@
     f.write('};\n\n')
 
   def GetByID(self, id_str):
-    if not isinstance(id_str, types.StringTypes):
+    if not isinstance(id_str, string_type):
       return id_str
     if id_str not in self.id_map:
       raise RuntimeError('Invalid $ref: ' + id_str)
@@ -941,12 +945,12 @@
     simple as looking up for corresponding ID in self.id_map, and replace the
     old index with the mapped index.
     """
-    self.schema_nodes = map(
-        partial(self.ResolveID, 1, SchemaNode), self.schema_nodes)
-    self.property_nodes = map(
-        partial(self.ResolveID, 1, PropertyNode), self.property_nodes)
-    self.properties_nodes = map(
-        partial(self.ResolveID, 3, PropertiesNode), self.properties_nodes)
+    self.schema_nodes = list(
+        map(partial(self.ResolveID, 1, SchemaNode), self.schema_nodes))
+    self.property_nodes = list(
+        map(partial(self.ResolveID, 1, PropertyNode), self.property_nodes))
+    self.properties_nodes = list(
+        map(partial(self.ResolveID, 3, PropertiesNode), self.properties_nodes))
 
   def FindSensitiveChildren(self):
     """Wrapper function, which calls FindSensitiveChildrenRecursive().
diff --git a/components/security_state/content/DEPS b/components/security_state/content/DEPS
index 65d176c9..42cbf7e 100644
--- a/components/security_state/content/DEPS
+++ b/components/security_state/content/DEPS
@@ -4,8 +4,8 @@
   "+content/public/common",
   "+content/public/test",
   "+third_party/boringssl/src/include",
-  # Allow inclusion of WebKit API headers (POD/enum only).
-  "+third_party/blink/public/platform/web_security_style.h",
+  # Allow inclusion of blink API headers (POD/enum only).
+  "+third_party/blink/public/common/security/security_style.h",
   "+ui/base",
 ]
 
diff --git a/components/security_state/content/content_utils.cc b/components/security_state/content/content_utils.cc
index e05fac557..9336738 100644
--- a/components/security_state/content/content_utils.cc
+++ b/components/security_state/content/content_utils.cc
@@ -36,26 +36,26 @@
 namespace {
 
 // Note: This is a lossy operation. Not all of the policies that can be
-// expressed by a SecurityLevel can be expressed by a blink::WebSecurityStyle.
-blink::WebSecurityStyle SecurityLevelToSecurityStyle(
+// expressed by a SecurityLevel can be expressed by a blink::SecurityStyle.
+blink::SecurityStyle SecurityLevelToSecurityStyle(
     security_state::SecurityLevel security_level) {
   switch (security_level) {
     case security_state::NONE:
     case security_state::WARNING:
-      return blink::kWebSecurityStyleNeutral;
+      return blink::SecurityStyle::kNeutral;
     case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
     case security_state::EV_SECURE:
     case security_state::SECURE:
-      return blink::kWebSecurityStyleSecure;
+      return blink::SecurityStyle::kSecure;
     case security_state::DANGEROUS:
-      return blink::kWebSecurityStyleInsecure;
+      return blink::SecurityStyle::kInsecure;
     case security_state::SECURITY_LEVEL_COUNT:
       NOTREACHED();
-      return blink::kWebSecurityStyleNeutral;
+      return blink::SecurityStyle::kNeutral;
   }
 
   NOTREACHED();
-  return blink::kWebSecurityStyleUnknown;
+  return blink::SecurityStyle::kUnknown;
 }
 
 void ExplainHTTPSecurity(
@@ -408,11 +408,11 @@
   return state;
 }
 
-blink::WebSecurityStyle GetSecurityStyle(
+blink::SecurityStyle GetSecurityStyle(
     security_state::SecurityLevel security_level,
     const security_state::VisibleSecurityState& visible_security_state,
     content::SecurityStyleExplanations* security_style_explanations) {
-  const blink::WebSecurityStyle security_style =
+  const blink::SecurityStyle security_style =
       SecurityLevelToSecurityStyle(security_level);
 
   if (visible_security_state.malicious_content_status !=
diff --git a/components/security_state/content/content_utils.h b/components/security_state/content/content_utils.h
index b50f187..46e2f06 100644
--- a/components/security_state/content/content_utils.h
+++ b/components/security_state/content/content_utils.h
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "components/security_state/core/security_state.h"
-#include "third_party/blink/public/platform/web_security_style.h"
+#include "third_party/blink/public/common/security/security_style.h"
 
 namespace content {
 struct SecurityStyleExplanations;
@@ -25,7 +25,7 @@
 // with the given |security_level| and |visible_security_state|. Populates
 // |security_style_explanations| to explain why the returned
 // SecurityStyle was chosen.
-blink::WebSecurityStyle GetSecurityStyle(
+blink::SecurityStyle GetSecurityStyle(
     security_state::SecurityLevel security_level,
     const security_state::VisibleSecurityState& visible_security_state,
     content::SecurityStyleExplanations* security_style_explanations);
diff --git a/components/security_state/content/content_utils_unittest.cc b/components/security_state/content/content_utils_unittest.cc
index af6ec8b..7dccd16 100644
--- a/components/security_state/content/content_utils_unittest.cc
+++ b/components/security_state/content/content_utils_unittest.cc
@@ -585,30 +585,30 @@
 }
 
 // Tests that a security level of WARNING produces
-// blink::WebSecurityStyleNeutral.
+// blink::kSecurityStyleNeutral.
 TEST(SecurityStateContentUtilsTest, HTTPWarning) {
   security_state::VisibleSecurityState visible_security_state;
   visible_security_state.url = GURL("http://scheme-is-not-cryptographic.test");
   content::SecurityStyleExplanations explanations;
-  blink::WebSecurityStyle security_style = GetSecurityStyle(
+  blink::SecurityStyle security_style = GetSecurityStyle(
       security_state::WARNING, visible_security_state, &explanations);
-  EXPECT_EQ(blink::kWebSecurityStyleNeutral, security_style);
+  EXPECT_EQ(blink::SecurityStyle::kNeutral, security_style);
   // Verify no explanation was shown.
   EXPECT_EQ(0u, explanations.neutral_explanations.size());
 }
 
 // Tests that a security level of DANGEROUS on an HTTP page with insecure form
-// edits produces blink::WebSecurityStyleInsecure and an explanation.
+// edits produces blink::SecurityStyleInsecure and an explanation.
 TEST(SecurityStateContentUtilsTest, HTTPDangerous) {
   security_state::VisibleSecurityState visible_security_state;
   visible_security_state.url = GURL("http://scheme-is-not-cryptographic.test");
   content::SecurityStyleExplanations explanations;
   visible_security_state.insecure_input_events.insecure_field_edited = true;
-  blink::WebSecurityStyle security_style = GetSecurityStyle(
+  blink::SecurityStyle security_style = GetSecurityStyle(
       security_state::DANGEROUS, visible_security_state, &explanations);
   // Verify that the security style was downgraded and an explanation shown
   // because a form was edited.
-  EXPECT_EQ(blink::kWebSecurityStyleInsecure, security_style);
+  EXPECT_EQ(blink::SecurityStyle::kInsecure, security_style);
   EXPECT_EQ(1u, explanations.insecure_explanations.size());
 }
 
diff --git a/components/signin/core/browser/chrome_connected_header_helper.cc b/components/signin/core/browser/chrome_connected_header_helper.cc
index 69098155..ec98e97 100644
--- a/components/signin/core/browser/chrome_connected_header_helper.cc
+++ b/components/signin/core/browser/chrome_connected_header_helper.cc
@@ -58,7 +58,7 @@
 // static
 std::string ChromeConnectedHeaderHelper::BuildRequestCookieIfPossible(
     const GURL& url,
-    const std::string& account_id,
+    const std::string& gaia_id,
     AccountConsistencyMethod account_consistency,
     const content_settings::CookieSettings* cookie_settings,
     int profile_mode_mask) {
@@ -66,7 +66,7 @@
   if (!chrome_connected_helper.ShouldBuildRequestHeader(url, cookie_settings))
     return "";
   return chrome_connected_helper.BuildRequestHeader(
-      false /* is_header_request */, url, account_id, profile_mode_mask);
+      false /* is_header_request */, url, gaia_id, profile_mode_mask);
 }
 
 // static
@@ -167,7 +167,7 @@
 std::string ChromeConnectedHeaderHelper::BuildRequestHeader(
     bool is_header_request,
     const GURL& url,
-    const std::string& account_id,
+    const std::string& gaia_id,
     int profile_mode_mask) {
 #if defined(OS_ANDROID)
   bool is_mice_enabled = base::FeatureList::IsEnabled(kMiceFeature);
@@ -183,16 +183,16 @@
 // filtered upstream and we want to enforce account consistency in Public
 // Sessions and Active Directory logins.
 #if !defined(OS_CHROMEOS)
-  if (account_id.empty() && !is_mice_enabled)
+  if (gaia_id.empty() && !is_mice_enabled)
     return std::string();
 #endif  // !defined(OS_CHROMEOS)
 
   std::vector<std::string> parts;
-  if (!account_id.empty() &&
+  if (!gaia_id.empty() &&
       IsUrlEligibleToIncludeGaiaId(url, is_header_request)) {
     // Only set the Gaia ID on domains that actually require it.
     parts.push_back(
-        base::StringPrintf("%s=%s", kGaiaIdAttrName, account_id.c_str()));
+        base::StringPrintf("%s=%s", kGaiaIdAttrName, gaia_id.c_str()));
   }
   parts.push_back(
       base::StringPrintf("%s=%s", kProfileModeAttrName,
diff --git a/components/signin/core/browser/chrome_connected_header_helper.h b/components/signin/core/browser/chrome_connected_header_helper.h
index 81831b2..2e42fbd 100644
--- a/components/signin/core/browser/chrome_connected_header_helper.h
+++ b/components/signin/core/browser/chrome_connected_header_helper.h
@@ -25,7 +25,7 @@
   // added to the request to |url|.
   static std::string BuildRequestCookieIfPossible(
       const GURL& url,
-      const std::string& account_id,
+      const std::string& gaia_id,
       AccountConsistencyMethod account_consistency,
       const content_settings::CookieSettings* cookie_settings,
       int profile_mode_mask);
@@ -39,7 +39,7 @@
   // empty string, in this case the header must not be added.
   std::string BuildRequestHeader(bool is_header_request,
                                  const GURL& url,
-                                 const std::string& account_id,
+                                 const std::string& gaia_id,
                                  int profile_mode_mask);
 
   // SigninHeaderHelper implementation:
diff --git a/components/signin/core/browser/dice_header_helper.cc b/components/signin/core/browser/dice_header_helper.cc
index 0c9880e..4d1bc24 100644
--- a/components/signin/core/browser/dice_header_helper.cc
+++ b/components/signin/core/browser/dice_header_helper.cc
@@ -194,7 +194,7 @@
 }
 
 std::string DiceHeaderHelper::BuildRequestHeader(
-    const std::string& sync_account_id,
+    const std::string& sync_gaia_id,
     const std::string& device_id) {
   std::vector<std::string> parts;
   parts.push_back(base::StringPrintf("version=%s", kDiceProtocolVersion));
@@ -202,8 +202,8 @@
                   GaiaUrls::GetInstance()->oauth2_chrome_client_id());
   if (!device_id.empty())
     parts.push_back("device_id=" + device_id);
-  if (!sync_account_id.empty())
-    parts.push_back("sync_account_id=" + sync_account_id);
+  if (!sync_gaia_id.empty())
+    parts.push_back("sync_account_id=" + sync_gaia_id);
 
   // Restrict Signin to Sync account only when fixing auth errors.
   std::string signin_mode = kRequestSigninAll;
diff --git a/components/signin/core/browser/dice_header_helper.h b/components/signin/core/browser/dice_header_helper.h
index d4711431..4d076f6 100644
--- a/components/signin/core/browser/dice_header_helper.h
+++ b/components/signin/core/browser/dice_header_helper.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "components/signin/core/browser/signin_header_helper.h"
 #include "components/signin/public/base/account_consistency_method.h"
+#include "google_apis/gaia/core_account_id.h"
 
 class GURL;
 
@@ -36,11 +37,11 @@
 
   // Returns the header value for Dice requests. Returns the empty string when
   // the header must not be added.
-  // |sync_account_id| is not empty if Sync is currently enabled for this
+  // |sync_gaia_id| is not empty if Sync is currently enabled for this
   // account.
   // |show_signout_confirmation| is true if Gaia must display the signout
   // confirmation dialog.
-  std::string BuildRequestHeader(const std::string& sync_account_id,
+  std::string BuildRequestHeader(const std::string& sync_gaia_id,
                                  const std::string& device_id);
 
   // SigninHeaderHelper implementation:
diff --git a/components/signin/core/browser/signin_header_helper.cc b/components/signin/core/browser/signin_header_helper.cc
index cf0a387..72bb55c9 100644
--- a/components/signin/core/browser/signin_header_helper.cc
+++ b/components/signin/core/browser/signin_header_helper.cc
@@ -88,12 +88,12 @@
 
 std::string BuildMirrorRequestCookieIfPossible(
     const GURL& url,
-    const std::string& account_id,
+    const std::string& gaia_id,
     AccountConsistencyMethod account_consistency,
     const content_settings::CookieSettings* cookie_settings,
     int profile_mode_mask) {
   return ChromeConnectedHeaderHelper::BuildRequestCookieIfPossible(
-      url, account_id, account_consistency, cookie_settings, profile_mode_mask);
+      url, gaia_id, account_consistency, cookie_settings, profile_mode_mask);
 }
 
 SigninHeaderHelper::SigninHeaderHelper() = default;
@@ -147,7 +147,7 @@
 void AppendOrRemoveMirrorRequestHeader(
     RequestAdapter* request,
     const GURL& redirect_url,
-    const std::string& account_id,
+    const std::string& gaia_id,
     AccountConsistencyMethod account_consistency,
     const content_settings::CookieSettings* cookie_settings,
     int profile_mode_mask) {
@@ -156,7 +156,7 @@
   std::string chrome_connected_header_value;
   if (chrome_connected_helper.ShouldBuildRequestHeader(url, cookie_settings)) {
     chrome_connected_header_value = chrome_connected_helper.BuildRequestHeader(
-        true /* is_header_request */, url, account_id, profile_mode_mask);
+        true /* is_header_request */, url, gaia_id, profile_mode_mask);
   }
   chrome_connected_helper.AppendOrRemoveRequestHeader(
       request, redirect_url, kChromeConnectedHeader,
@@ -166,7 +166,7 @@
 bool AppendOrRemoveDiceRequestHeader(
     RequestAdapter* request,
     const GURL& redirect_url,
-    const std::string& account_id,
+    const std::string& gaia_id,
     bool sync_enabled,
     AccountConsistencyMethod account_consistency,
     const content_settings::CookieSettings* cookie_settings,
@@ -177,7 +177,7 @@
   std::string dice_header_value;
   if (dice_helper.ShouldBuildRequestHeader(url, cookie_settings)) {
     dice_header_value = dice_helper.BuildRequestHeader(
-        sync_enabled ? account_id : std::string(), device_id);
+        sync_enabled ? gaia_id : std::string(), device_id);
   }
   return dice_helper.AppendOrRemoveRequestHeader(
       request, redirect_url, kDiceRequestHeader, dice_header_value);
diff --git a/components/signin/core/browser/signin_header_helper.h b/components/signin/core/browser/signin_header_helper.h
index ac718de..20c4e4dc 100644
--- a/components/signin/core/browser/signin_header_helper.h
+++ b/components/signin/core/browser/signin_header_helper.h
@@ -12,6 +12,7 @@
 #include "components/prefs/pref_member.h"
 #include "components/signin/public/base/account_consistency_method.h"
 #include "components/signin/public/base/signin_buildflags.h"
+#include "google_apis/gaia/core_account_id.h"
 #include "url/gurl.h"
 
 namespace content_settings {
@@ -204,7 +205,7 @@
 // added to the request to |url|.
 std::string BuildMirrorRequestCookieIfPossible(
     const GURL& url,
-    const std::string& account_id,
+    const std::string& gaia_id,
     AccountConsistencyMethod account_consistency,
     const content_settings::CookieSettings* cookie_settings,
     int profile_mode_mask);
@@ -215,7 +216,7 @@
 void AppendOrRemoveMirrorRequestHeader(
     RequestAdapter* request,
     const GURL& redirect_url,
-    const std::string& account_id,
+    const std::string& gaia_id,
     AccountConsistencyMethod account_consistency,
     const content_settings::CookieSettings* cookie_settings,
     int profile_mode_mask);
@@ -227,7 +228,7 @@
 bool AppendOrRemoveDiceRequestHeader(
     RequestAdapter* request,
     const GURL& redirect_url,
-    const std::string& account_id,
+    const std::string& gaia_id,
     bool sync_enabled,
     AccountConsistencyMethod account_consistency,
     const content_settings::CookieSettings* cookie_settings,
diff --git a/components/signin/core/browser/signin_header_helper_unittest.cc b/components/signin/core/browser/signin_header_helper_unittest.cc
index 8e7cb76..91eb1bf2 100644
--- a/components/signin/core/browser/signin_header_helper_unittest.cc
+++ b/components/signin/core/browser/signin_header_helper_unittest.cc
@@ -50,10 +50,10 @@
   void TearDown() override { settings_map_->ShutdownOnUIThread(); }
 
   void CheckMirrorCookieRequest(const GURL& url,
-                                const std::string& account_id,
+                                const std::string& gaia_id,
                                 const std::string& expected_request) {
     EXPECT_EQ(BuildMirrorRequestCookieIfPossible(
-                  url, account_id, account_consistency_, cookie_settings_.get(),
+                  url, gaia_id, account_consistency_, cookie_settings_.get(),
                   PROFILE_MODE_DEFAULT),
               expected_request);
   }
diff --git a/components/signin/internal/identity_manager/primary_account_manager.cc b/components/signin/internal/identity_manager/primary_account_manager.cc
index 330f01fe..b96c001 100644
--- a/components/signin/internal/identity_manager/primary_account_manager.cc
+++ b/components/signin/internal/identity_manager/primary_account_manager.cc
@@ -207,7 +207,7 @@
   primary_account_info_ = account_info;
 
   PrefService* prefs = client_->GetPrefs();
-  const std::string& account_id = primary_account_info_.account_id;
+  const std::string& account_id = primary_account_info_.account_id.id;
   if (account_id.empty()) {
     DCHECK(!consented_to_sync);
     prefs->ClearPref(prefs::kGoogleServicesAccountId);
diff --git a/components/sync/driver/BUILD.gn b/components/sync/driver/BUILD.gn
index d30baec..5b27a3f6 100644
--- a/components/sync/driver/BUILD.gn
+++ b/components/sync/driver/BUILD.gn
@@ -115,6 +115,9 @@
     "//components/signin/public/identity_manager",
     "//components/version_info",
     "//components/version_info:generate_version_info",
+
+    # TODO(crbug.com/1012226): Remove when VAPID migration is over.
+    "//crypto",
     "//services/network/public/cpp",
     "//ui/base",
   ]
diff --git a/components/sync/driver/DEPS b/components/sync/driver/DEPS
index fe63a79..d62b11c 100644
--- a/components/sync/driver/DEPS
+++ b/components/sync/driver/DEPS
@@ -17,6 +17,8 @@
   "+components/sync/syncable",
   "+components/sync/test",
   "+components/sync_preferences",
+  # TODO(crbug.com/1012226): Remove when VAPID migration is over.
+  "+crypto",
   "+google/cacheinvalidation",
   "+net",
   "+policy",
diff --git a/components/sync/driver/fake_sync_service.cc b/components/sync/driver/fake_sync_service.cc
index ad76d78..1fafb89 100644
--- a/components/sync/driver/fake_sync_service.cc
+++ b/components/sync/driver/fake_sync_service.cc
@@ -94,6 +94,10 @@
   return false;
 }
 
+std::string FakeSyncService::GetExperimentalAuthenticationId() const {
+  return std::string();
+}
+
 UserShare* FakeSyncService::GetUserShare() const {
   return user_share_.get();
 }
diff --git a/components/sync/driver/fake_sync_service.h b/components/sync/driver/fake_sync_service.h
index bef6501..84a6cfc 100644
--- a/components/sync/driver/fake_sync_service.h
+++ b/components/sync/driver/fake_sync_service.h
@@ -46,6 +46,7 @@
   GoogleServiceAuthError GetAuthError() const override;
   base::Time GetAuthErrorTime() const override;
   bool RequiresClientUpgrade() const override;
+  std::string GetExperimentalAuthenticationId() const override;
   UserShare* GetUserShare() const override;
   void DataTypePreconditionChanged(syncer::ModelType type) override;
   SyncTokenStatus GetSyncTokenStatusForDebugging() const override;
diff --git a/components/sync/driver/glue/sync_engine_backend.cc b/components/sync/driver/glue/sync_engine_backend.cc
index 9e76e8d..c3ddaf2 100644
--- a/components/sync/driver/glue/sync_engine_backend.cc
+++ b/components/sync/driver/glue/sync_engine_backend.cc
@@ -114,7 +114,8 @@
     const SyncCycleSnapshot& snapshot) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   host_.Call(FROM_HERE, &SyncEngineImpl::HandleSyncCycleCompletedOnFrontendLoop,
-             snapshot);
+             snapshot,
+             sync_manager_->GetEncryptionHandler()->GetLastKeystoreKey());
 }
 
 void SyncEngineBackend::DoRefreshTypes(ModelTypeSet types) {
@@ -476,7 +477,8 @@
       registrar_->GetLastConfiguredTypes(), js_backend_, debug_info_listener_,
       base::Passed(sync_manager_->GetModelTypeConnectorProxy()),
       sync_manager_->cache_guid(), sync_manager_->birthday(),
-      sync_manager_->bag_of_chips());
+      sync_manager_->bag_of_chips(),
+      sync_manager_->GetEncryptionHandler()->GetLastKeystoreKey());
 
   js_backend_.Reset();
   debug_info_listener_.Reset();
diff --git a/components/sync/driver/glue/sync_engine_impl.cc b/components/sync/driver/glue/sync_engine_impl.cc
index 46c4314..25d38e5 100644
--- a/components/sync/driver/glue/sync_engine_impl.cc
+++ b/components/sync/driver/glue/sync_engine_impl.cc
@@ -321,7 +321,8 @@
     std::unique_ptr<ModelTypeConnector> model_type_connector,
     const std::string& cache_guid,
     const std::string& birthday,
-    const std::string& bag_of_chips) {
+    const std::string& bag_of_chips,
+    const std::string& last_keystore_key) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   model_type_connector_ = std::move(model_type_connector);
@@ -339,7 +340,7 @@
 
   host_->OnEngineInitialized(initial_types, js_backend, debug_info_listener,
                              cache_guid, birthday, bag_of_chips,
-                             /*success=*/true);
+                             last_keystore_key, /*success=*/true);
 }
 
 void SyncEngineImpl::HandleInitializationFailureOnFrontendLoop() {
@@ -348,17 +349,19 @@
                              WeakHandle<DataTypeDebugInfoListener>(),
                              /*cache_guid=*/"",
                              /*birthday=*/"", /*bag_of_chips=*/"",
+                             /*last_keystore_key=*/"",
                              /*success=*/false);
 }
 
 void SyncEngineImpl::HandleSyncCycleCompletedOnFrontendLoop(
-    const SyncCycleSnapshot& snapshot) {
+    const SyncCycleSnapshot& snapshot,
+    const std::string& last_keystore_key) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Process any changes to the datatypes we're syncing.
   // TODO(sync): add support for removing types.
   if (IsInitialized()) {
-    host_->OnSyncCycleCompleted(snapshot);
+    host_->OnSyncCycleCompleted(snapshot, last_keystore_key);
   }
 }
 
diff --git a/components/sync/driver/glue/sync_engine_impl.h b/components/sync/driver/glue/sync_engine_impl.h
index 08e6222..9c8c807 100644
--- a/components/sync/driver/glue/sync_engine_impl.h
+++ b/components/sync/driver/glue/sync_engine_impl.h
@@ -126,7 +126,8 @@
       std::unique_ptr<ModelTypeConnector> model_type_connector,
       const std::string& cache_guid,
       const std::string& birthday,
-      const std::string& bag_of_chips);
+      const std::string& bag_of_chips,
+      const std::string& last_keystore_key);
 
   // Forwards a ProtocolEvent to the host. Will not be called unless a call to
   // SetForwardProtocolEvents() explicitly requested that we start forwarding
@@ -170,7 +171,8 @@
   // Called from SyncEngineBackend::OnSyncCycleCompleted to handle updating
   // frontend thread components.
   void HandleSyncCycleCompletedOnFrontendLoop(
-      const SyncCycleSnapshot& snapshot);
+      const SyncCycleSnapshot& snapshot,
+      const std::string& last_keystore_key);
 
   // Let the front end handle the actionable error event.
   void HandleActionableErrorEventOnFrontendLoop(
diff --git a/components/sync/driver/glue/sync_engine_impl_unittest.cc b/components/sync/driver/glue/sync_engine_impl_unittest.cc
index 5e7be86..69310c4 100644
--- a/components/sync/driver/glue/sync_engine_impl_unittest.cc
+++ b/components/sync/driver/glue/sync_engine_impl_unittest.cc
@@ -78,6 +78,7 @@
                            const std::string&,
                            const std::string&,
                            const std::string&,
+                           const std::string&,
                            bool success) override {
     EXPECT_EQ(expect_success_, success);
     set_engine_types_.Run(initial_types);
diff --git a/components/sync/driver/mock_sync_service.h b/components/sync/driver/mock_sync_service.h
index 0f3a1696..54199bb 100644
--- a/components/sync/driver/mock_sync_service.h
+++ b/components/sync/driver/mock_sync_service.h
@@ -40,6 +40,7 @@
   MOCK_CONST_METHOD0(GetAuthError, GoogleServiceAuthError());
   MOCK_CONST_METHOD0(GetAuthErrorTime, base::Time());
   MOCK_CONST_METHOD0(RequiresClientUpgrade, bool());
+  MOCK_CONST_METHOD0(GetExperimentalAuthenticationId, std::string());
 
   MOCK_METHOD0(GetSetupInProgressHandle,
                std::unique_ptr<SyncSetupInProgressHandle>());
diff --git a/components/sync/driver/profile_sync_service.cc b/components/sync/driver/profile_sync_service.cc
index b20443c..fed83bb 100644
--- a/components/sync/driver/profile_sync_service.cc
+++ b/components/sync/driver/profile_sync_service.cc
@@ -41,6 +41,7 @@
 #include "components/sync/model/sync_error.h"
 #include "components/sync/syncable/user_share.h"
 #include "components/version_info/version_info_values.h"
+#include "crypto/sha2.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace syncer {
@@ -593,6 +594,8 @@
   crypto_.Reset();
   expect_sync_configuration_aborted_ = false;
   last_snapshot_ = SyncCycleSnapshot();
+  last_keystore_key_.clear();
+
   if (!IsLocalSyncEnabled()) {
     auth_manager_->ConnectionClosed();
   }
@@ -811,6 +814,7 @@
     const std::string& cache_guid,
     const std::string& birthday,
     const std::string& bag_of_chips,
+    const std::string& last_keystore_key,
     bool success) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -843,6 +847,8 @@
   sync_prefs_.SetBirthday(birthday);
   sync_prefs_.SetBagOfChips(bag_of_chips);
 
+  last_keystore_key_ = last_keystore_key;
+
   if (protocol_event_observers_.might_have_observers()) {
     engine_->RequestBufferedProtocolEventsAndEnableForwarding();
   }
@@ -892,10 +898,12 @@
 }
 
 void ProfileSyncService::OnSyncCycleCompleted(
-    const SyncCycleSnapshot& snapshot) {
+    const SyncCycleSnapshot& snapshot,
+    const std::string& last_keystore_key) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   last_snapshot_ = snapshot;
+  last_keystore_key_ = last_keystore_key;
 
   UpdateLastSyncedTime();
   if (!snapshot.poll_finish_time().is_null())
@@ -1111,6 +1119,26 @@
   return last_actionable_error_.action == UPGRADE_CLIENT;
 }
 
+std::string ProfileSyncService::GetExperimentalAuthenticationId() const {
+  // Dependent fields are first populated when the sync engine is initialized,
+  // when usually all except keystore keys are guaranteed to be available.
+  // Keystore keys are usually available initially too, but in rare cases they
+  // should arrive in later sync cycles.
+  if (last_keystore_key_.empty()) {
+    return std::string();
+  }
+
+  // A separator is not strictly needed but it's adopted here as good practice.
+  const std::string kSeparator("|");
+  const std::string gaia_id = GetAuthenticatedAccountInfo().gaia;
+  const std::string birthday = sync_prefs_.GetBirthday();
+  DCHECK(!gaia_id.empty());
+  DCHECK(!birthday.empty());
+
+  return crypto::SHA256HashString(gaia_id + kSeparator + birthday + kSeparator +
+                                  last_keystore_key_);
+}
+
 bool ProfileSyncService::CanConfigureDataTypes(
     bool bypass_setup_in_progress_check) const {
   // TODO(crbug.com/856179): Arguably, IsSetupInProgress() shouldn't prevent
diff --git a/components/sync/driver/profile_sync_service.h b/components/sync/driver/profile_sync_service.h
index 4e68e16..cb65913 100644
--- a/components/sync/driver/profile_sync_service.h
+++ b/components/sync/driver/profile_sync_service.h
@@ -126,6 +126,7 @@
   bool RequiresClientUpgrade() const override;
   std::unique_ptr<SyncSetupInProgressHandle> GetSetupInProgressHandle()
       override;
+  std::string GetExperimentalAuthenticationId() const override;
   bool IsSetupInProgress() const override;
   ModelTypeSet GetRegisteredDataTypes() const override;
   ModelTypeSet GetPreferredDataTypes() const override;
@@ -166,8 +167,10 @@
       const std::string& cache_guid,
       const std::string& birthday,
       const std::string& bag_of_chips,
+      const std::string& last_keystore_key,
       bool success) override;
-  void OnSyncCycleCompleted(const SyncCycleSnapshot& snapshot) override;
+  void OnSyncCycleCompleted(const SyncCycleSnapshot& snapshot,
+                            const std::string& last_keystore_key) override;
   void OnProtocolEvent(const ProtocolEvent& event) override;
   void OnDirectoryTypeCommitCounterUpdated(
       ModelType type,
@@ -421,6 +424,11 @@
   // OnEngineInitialized().
   bool is_first_time_sync_configure_;
 
+  // Last known keystore key, populated after engine initialization.
+  // TODO(crbug.com/1012226): Remove |last_keystore_key_| when VAPID migration
+  // is over.
+  std::string last_keystore_key_;
+
   // Number of UIs currently configuring the Sync service. When this number
   // is decremented back to zero, Sync setup is marked no longer in progress.
   int outstanding_setup_in_progress_handles_ = 0;
diff --git a/components/sync/driver/profile_sync_service_startup_unittest.cc b/components/sync/driver/profile_sync_service_startup_unittest.cc
index 4d60102..4fb8c1d 100644
--- a/components/sync/driver/profile_sync_service_startup_unittest.cc
+++ b/components/sync/driver/profile_sync_service_startup_unittest.cc
@@ -636,6 +636,7 @@
                                       WeakHandle<DataTypeDebugInfoListener>(),
                                       "test-guid", "test-birthday",
                                       "test-bag-of-chips",
+                                      /*last_keystore_key=*/std::string(),
                                       /*success=*/true);
   ASSERT_TRUE(sync_service()->IsEngineInitialized());
   EXPECT_EQ(SyncService::TransportState::PENDING_DESIRED_CONFIGURATION,
@@ -717,6 +718,7 @@
                                       WeakHandle<DataTypeDebugInfoListener>(),
                                       "test-guid", "test-birthday",
                                       "test-bag-of-chips",
+                                      /*last_keystore_key=*/std::string(),
                                       /*success=*/true);
   ON_CALL(*data_type_manager, state())
       .WillByDefault(Return(DataTypeManager::CONFIGURING));
diff --git a/components/sync/driver/profile_sync_service_unittest.cc b/components/sync/driver/profile_sync_service_unittest.cc
index d650ef7d..36efe9f 100644
--- a/components/sync/driver/profile_sync_service_unittest.cc
+++ b/components/sync/driver/profile_sync_service_unittest.cc
@@ -19,6 +19,7 @@
 #include "base/values.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
+#include "components/signin/public/identity_manager/identity_test_utils.h"
 #include "components/signin/public/identity_manager/primary_account_mutator.h"
 #include "components/sync/base/pref_names.h"
 #include "components/sync/base/user_demographics.h"
@@ -35,6 +36,7 @@
 #include "components/sync/engine/fake_sync_engine.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "components/version_info/version_info_values.h"
+#include "crypto/sha2.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/metrics_proto/user_demographics.pb.h"
@@ -51,6 +53,8 @@
 // |kNowTimeInStringFormat|.
 constexpr int kOldEnoughForDemographicsUserBirthYear = 1983;
 
+constexpr char kTestUser[] = "test_user@gmail.com";
+
 // Now time in string format.
 constexpr char kNowTimeInStringFormat[] = "23 Mar 2019 16:00:00 UDT";
 
@@ -167,9 +171,7 @@
     ShutdownAndDeleteService();
   }
 
-  void SignIn() {
-    identity_test_env()->MakePrimaryAccountAvailable("test_user@gmail.com");
-  }
+  void SignIn() { identity_test_env()->MakePrimaryAccountAvailable(kTestUser); }
 
   void CreateService(ProfileSyncService::StartBehavior behavior) {
     DCHECK(!service_);
@@ -1463,5 +1465,23 @@
   EXPECT_TRUE(HasBirthYearOffset(prefs()));
 }
 
+TEST_F(ProfileSyncServiceTest, GetExperimentalAuthenticationId) {
+  SignIn();
+  CreateService(ProfileSyncService::AUTO_START);
+  InitializeForNthSync();
+  ASSERT_EQ(SyncService::TransportState::ACTIVE,
+            service()->GetTransportState());
+
+  const std::string kSeparator("|");
+  const std::string kGaiaId = signin::GetTestGaiaIdForEmail(kTestUser);
+
+  const std::string authentication_id_before_hashing =
+      kGaiaId + kSeparator + FakeSyncEngine::kTestBirthday + kSeparator +
+      FakeSyncEngine::kTestKeystoreKey;
+
+  EXPECT_EQ(crypto::SHA256HashString(authentication_id_before_hashing),
+            service()->GetExperimentalAuthenticationId());
+}
+
 }  // namespace
 }  // namespace syncer
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h
index 5a5fc3a..3ccbbe749 100644
--- a/components/sync/driver/sync_service.h
+++ b/components/sync/driver/sync_service.h
@@ -240,6 +240,14 @@
   // Sync to work.
   virtual bool RequiresClientUpgrade() const = 0;
 
+  // Returns a high-entropy randomly-generated ID that is unique to a user and
+  // sync-ed across devices via Nigori. Populated when the transport state
+  // becomes CONFIGURING. Returns an empty string if not available. Consumers
+  // of this ID should observe for changes via
+  // SyncServiceObserver::OnSyncCycleCompleted().
+  // TODO(crbug.com/1012226): Remove when VAPID migration is over.
+  virtual std::string GetExperimentalAuthenticationId() const = 0;
+
   //////////////////////////////////////////////////////////////////////////////
   // DERIVED STATE ACCESS
   //////////////////////////////////////////////////////////////////////////////
diff --git a/components/sync/driver/test_sync_service.cc b/components/sync/driver/test_sync_service.cc
index dbbc03a..82f2ac07 100644
--- a/components/sync/driver/test_sync_service.cc
+++ b/components/sync/driver/test_sync_service.cc
@@ -170,6 +170,10 @@
          syncer::UPGRADE_CLIENT;
 }
 
+std::string TestSyncService::GetExperimentalAuthenticationId() const {
+  return std::string();
+}
+
 std::unique_ptr<SyncSetupInProgressHandle>
 TestSyncService::GetSetupInProgressHandle() {
   return nullptr;
diff --git a/components/sync/driver/test_sync_service.h b/components/sync/driver/test_sync_service.h
index 803b8ab..e884ab9 100644
--- a/components/sync/driver/test_sync_service.h
+++ b/components/sync/driver/test_sync_service.h
@@ -63,6 +63,7 @@
   GoogleServiceAuthError GetAuthError() const override;
   base::Time GetAuthErrorTime() const override;
   bool RequiresClientUpgrade() const override;
+  std::string GetExperimentalAuthenticationId() const override;
 
   std::unique_ptr<SyncSetupInProgressHandle> GetSetupInProgressHandle()
       override;
diff --git a/components/sync/engine/fake_sync_engine.cc b/components/sync/engine/fake_sync_engine.cc
index c274449..ffcdf0b8 100644
--- a/components/sync/engine/fake_sync_engine.cc
+++ b/components/sync/engine/fake_sync_engine.cc
@@ -11,12 +11,10 @@
 #include "components/sync/model/model_type_controller_delegate.h"
 
 namespace syncer {
-namespace {
 
-const char kTestCacheGuid[] = "test-guid";
-const char kTestBirthday[] = "1";
-
-}  // namespace
+constexpr char FakeSyncEngine::kTestCacheGuid[];
+constexpr char FakeSyncEngine::kTestBirthday[];
+constexpr char FakeSyncEngine::kTestKeystoreKey[];
 
 FakeSyncEngine::FakeSyncEngine() {}
 FakeSyncEngine::~FakeSyncEngine() {}
@@ -24,10 +22,10 @@
 void FakeSyncEngine::Initialize(InitParams params) {
   bool success = !fail_initial_download_;
   initialized_ = success;
-  params.host->OnEngineInitialized(ModelTypeSet(), WeakHandle<JsBackend>(),
-                                   WeakHandle<DataTypeDebugInfoListener>(),
-                                   kTestCacheGuid, kTestBirthday,
-                                   /*bag_of_chips=*/"", success);
+  params.host->OnEngineInitialized(
+      ModelTypeSet(), WeakHandle<JsBackend>(),
+      WeakHandle<DataTypeDebugInfoListener>(), kTestCacheGuid, kTestBirthday,
+      /*bag_of_chips=*/"", kTestKeystoreKey, success);
 }
 
 bool FakeSyncEngine::IsInitialized() const {
diff --git a/components/sync/engine/fake_sync_engine.h b/components/sync/engine/fake_sync_engine.h
index c6ced2a..e55d0eb 100644
--- a/components/sync/engine/fake_sync_engine.h
+++ b/components/sync/engine/fake_sync_engine.h
@@ -24,6 +24,10 @@
 // behavior.
 class FakeSyncEngine : public SyncEngine {
  public:
+  static constexpr char kTestCacheGuid[] = "test-guid";
+  static constexpr char kTestBirthday[] = "1";
+  static constexpr char kTestKeystoreKey[] = "test-keystore-key";
+
   FakeSyncEngine();
   ~FakeSyncEngine() override;
 
diff --git a/components/sync/engine/sync_encryption_handler.h b/components/sync/engine/sync_encryption_handler.h
index bb048d4..e0a3fc9 100644
--- a/components/sync/engine/sync_encryption_handler.h
+++ b/components/sync/engine/sync_encryption_handler.h
@@ -45,8 +45,6 @@
 // TODO(crbug.com/1010397): Rename this class.
 class SyncEncryptionHandler {
  public:
-  class NigoriState;
-
   static constexpr PassphraseType kInitialPassphraseType =
       PassphraseType::kImplicitPassphrase;
 
@@ -132,15 +130,9 @@
 
     // The user has set a passphrase using this device.
     // TODO(treib): This method is only overridden in tests which use it to
-    // capture the NigoriState; we should find a better way to do that.
+    // capture the Nigori state; we should find a better way to do that.
     virtual void OnLocalSetPassphraseEncryption(
-        const NigoriState& nigori_state) {}
-  };
-
-  class NigoriState {
-   public:
-    NigoriState() {}
-    sync_pb::NigoriSpecifics nigori_specifics;
+        const sync_pb::NigoriSpecifics& specifics) {}
   };
 
   SyncEncryptionHandler();
@@ -199,6 +191,10 @@
   // check whether keystore keys need to be requested from the server.
   virtual KeystoreKeysHandler* GetKeystoreKeysHandler() = 0;
 
+  // Returns the last known keystore key or an empty string if none available.
+  // TODO(crbug.com/1012226): Remove API when VAPID migration is over.
+  virtual std::string GetLastKeystoreKey() const = 0;
+
   // The set of types that are always encrypted.
   static ModelTypeSet SensitiveTypes();
 };
diff --git a/components/sync/engine/sync_engine_host.h b/components/sync/engine/sync_engine_host.h
index c345abb5..6832bf3 100644
--- a/components/sync/engine/sync_engine_host.h
+++ b/components/sync/engine/sync_engine_host.h
@@ -36,6 +36,8 @@
   //
   // |js_backend| is what about:sync interacts with. It is initialized only if
   // |success| is true.
+  // TODO(crbug.com/1012226): Remove |last_keystore_key| when VAPID migration is
+  // over.
   virtual void OnEngineInitialized(
       ModelTypeSet initial_types,
       const WeakHandle<JsBackend>& js_backend,
@@ -43,10 +45,12 @@
       const std::string& cache_guid,
       const std::string& birthday,
       const std::string& bag_of_chips,
+      const std::string& last_keystore_key,
       bool success) = 0;
 
   // The engine queried the server recently and received some updates.
-  virtual void OnSyncCycleCompleted(const SyncCycleSnapshot& snapshot) = 0;
+  virtual void OnSyncCycleCompleted(const SyncCycleSnapshot& snapshot,
+                                    const std::string& last_keystore_key) = 0;
 
   // Informs the host of some network event. These notifications are disabled by
   // default and must be enabled through an explicit request to the SyncEngine.
diff --git a/components/sync/engine/sync_engine_host_stub.cc b/components/sync/engine/sync_engine_host_stub.cc
index 255e9a77..43f98c5a4 100644
--- a/components/sync/engine/sync_engine_host_stub.cc
+++ b/components/sync/engine/sync_engine_host_stub.cc
@@ -16,10 +16,12 @@
     const std::string& cache_guid,
     const std::string& birthday,
     const std::string& bag_of_chips,
+    const std::string& last_keystore_key,
     bool success) {}
 
 void SyncEngineHostStub::OnSyncCycleCompleted(
-    const SyncCycleSnapshot& snapshot) {}
+    const SyncCycleSnapshot& snapshot,
+    const std::string& last_keystore_key) {}
 
 void SyncEngineHostStub::OnProtocolEvent(const ProtocolEvent& event) {}
 
diff --git a/components/sync/engine/sync_engine_host_stub.h b/components/sync/engine/sync_engine_host_stub.h
index edb7928..8e709a82 100644
--- a/components/sync/engine/sync_engine_host_stub.h
+++ b/components/sync/engine/sync_engine_host_stub.h
@@ -24,8 +24,10 @@
       const std::string& cache_guid,
       const std::string& birthday,
       const std::string& bag_of_chips,
+      const std::string& last_keystore_key,
       bool success) override;
-  void OnSyncCycleCompleted(const SyncCycleSnapshot& snapshot) override;
+  void OnSyncCycleCompleted(const SyncCycleSnapshot& snapshot,
+                            const std::string& last_keystore_key) override;
   void OnProtocolEvent(const ProtocolEvent& event) override;
   void OnDirectoryTypeCommitCounterUpdated(
       ModelType type,
diff --git a/components/sync/engine_impl/sync_encryption_handler_impl.cc b/components/sync/engine_impl/sync_encryption_handler_impl.cc
index 9f91563e..4e9f226 100644
--- a/components/sync/engine_impl/sync_encryption_handler_impl.cc
+++ b/components/sync/engine_impl/sync_encryption_handler_impl.cc
@@ -769,6 +769,12 @@
   return this;
 }
 
+std::string SyncEncryptionHandlerImpl::GetLastKeystoreKey() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  syncable::ReadTransaction trans(FROM_HERE, user_share_->directory.get());
+  return keystore_key_;
+}
+
 // Note: this is called from within a syncable transaction, so we need to post
 // tasks if we want to do any work that creates a new sync_api transaction.
 bool SyncEncryptionHandlerImpl::ApplyNigoriUpdate(
@@ -933,8 +939,8 @@
   return custom_passphrase_time_;
 }
 
-void SyncEncryptionHandlerImpl::RestoreNigori(
-    const SyncEncryptionHandler::NigoriState& nigori_state) {
+void SyncEncryptionHandlerImpl::RestoreNigoriForTesting(
+    const sync_pb::NigoriSpecifics& nigori_specifics) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   WriteTransaction trans(FROM_HERE, user_share_);
@@ -957,11 +963,11 @@
                                        syncable::GET_TYPE_ROOT, NIGORI);
   DCHECK(mutable_entry.good());
   sync_pb::EntitySpecifics specifics;
-  specifics.mutable_nigori()->CopyFrom(nigori_state.nigori_specifics);
+  *specifics.mutable_nigori() = nigori_specifics;
   mutable_entry.PutSpecifics(specifics);
 
   // Update our state based on the saved nigori node.
-  ApplyNigoriUpdate(nigori_state.nigori_specifics, trans.GetWrappedTrans());
+  ApplyNigoriUpdate(nigori_specifics, trans.GetWrappedTrans());
 }
 
 DirectoryCryptographer*
@@ -1424,14 +1430,13 @@
   WriteNode nigori_node(trans);
   BaseNode::InitByLookupResult init_result = nigori_node.InitTypeRoot(NIGORI);
   DCHECK_EQ(init_result, BaseNode::INIT_OK);
-  NigoriState nigori_state;
-  nigori_state.nigori_specifics = nigori_node.GetNigoriSpecifics();
-  DCHECK(nigori_state.nigori_specifics.passphrase_type() ==
+  sync_pb::NigoriSpecifics nigori_specifics = nigori_node.GetNigoriSpecifics();
+  DCHECK(nigori_specifics.passphrase_type() ==
              sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE ||
-         nigori_state.nigori_specifics.passphrase_type() ==
+         nigori_specifics.passphrase_type() ==
              sync_pb::NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE);
   for (auto& observer : observers_) {
-    observer.OnLocalSetPassphraseEncryption(nigori_state);
+    observer.OnLocalSetPassphraseEncryption(nigori_specifics);
   }
 }
 
diff --git a/components/sync/engine_impl/sync_encryption_handler_impl.h b/components/sync/engine_impl/sync_encryption_handler_impl.h
index db85ef6..3380a6e 100644
--- a/components/sync/engine_impl/sync_encryption_handler_impl.h
+++ b/components/sync/engine_impl/sync_encryption_handler_impl.h
@@ -73,6 +73,7 @@
   bool IsEncryptEverythingEnabled() const override;
   base::Time GetKeystoreMigrationTime() const override;
   KeystoreKeysHandler* GetKeystoreKeysHandler() override;
+  std::string GetLastKeystoreKey() const override;
 
   // NigoriHandler implementation.
   // Note: all methods are invoked while the caller holds a transaction.
@@ -106,7 +107,8 @@
   // Restore a saved nigori obtained from OnLocalSetPassphraseEncryption.
   //
   // Writes the nigori to the Directory and updates the Cryptographer.
-  void RestoreNigori(const SyncEncryptionHandler::NigoriState& nigori_state);
+  void RestoreNigoriForTesting(
+      const sync_pb::NigoriSpecifics& nigori_specifics);
 
   // Returns mutable DirectoryCryptographer, used only in tests to manipulate it
   // directly.
diff --git a/components/sync/engine_impl/sync_encryption_handler_impl_unittest.cc b/components/sync/engine_impl/sync_encryption_handler_impl_unittest.cc
index 0c93b3a..d5c37bd 100644
--- a/components/sync/engine_impl/sync_encryption_handler_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_encryption_handler_impl_unittest.cc
@@ -84,7 +84,7 @@
                void(PassphraseType,
                     base::Time));  // NOLINT
   MOCK_METHOD1(OnLocalSetPassphraseEncryption,
-               void(const SyncEncryptionHandler::NigoriState&));  // NOLINT
+               void(const sync_pb::NigoriSpecifics&));  // NOLINT
 };
 
 }  // namespace
@@ -547,7 +547,7 @@
       int64_t migration_time,
       const std::string& passphrase,
       const std::string& bootstrap_token,
-      const SyncEncryptionHandler::NigoriState& nigori_state,
+      const sync_pb::NigoriSpecifics& nigori_specifics,
       PassphraseType passphrase_type,
       const base::Optional<KeyDerivationParams>& key_derivation_params) {
     TearDown();
@@ -559,7 +559,7 @@
         .Times(AnyNumber());
     EXPECT_CALL(*observer(), OnPassphraseTypeChanged(passphrase_type, _));
     EXPECT_CALL(*observer(), OnEncryptionComplete());
-    encryption_handler()->RestoreNigori(nigori_state);
+    encryption_handler()->RestoreNigoriForTesting(nigori_specifics);
     encryption_handler()->Init();
     Mock::VerifyAndClearExpectations(observer());
     VerifyMigratedNigoriWithTimestamp(migration_time, passphrase_type,
@@ -1015,9 +1015,9 @@
               OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN))
       .WillOnce(testing::SaveArg<0>(&captured_bootstrap_token));
   EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, true));
-  SyncEncryptionHandler::NigoriState captured_nigori_state;
+  sync_pb::NigoriSpecifics captured_nigori_specifics;
   EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_))
-      .WillOnce(testing::SaveArg<0>(&captured_nigori_state));
+      .WillOnce(testing::SaveArg<0>(&captured_nigori_specifics));
   EXPECT_CALL(*observer(), OnEncryptionComplete()).Times(2);
   EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
   encryption_handler()->SetDecryptionPassphrase(kOtherKey);
@@ -1030,7 +1030,7 @@
 
   VerifyRestoreAfterExplicitPaspshrase(
       TimeToProtoTime(migration_time), kOtherKey, captured_bootstrap_token,
-      captured_nigori_state, PassphraseType::kCustomPassphrase,
+      captured_nigori_specifics, PassphraseType::kCustomPassphrase,
       {KeyDerivationParams::CreateForPbkdf2()});
 }
 
@@ -1080,9 +1080,9 @@
   encryption_handler()->Init();
   Mock::VerifyAndClearExpectations(observer());
   EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, true));
-  SyncEncryptionHandler::NigoriState captured_nigori_state;
+  sync_pb::NigoriSpecifics captured_nigori_specifics;
   EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_))
-      .WillOnce(testing::SaveArg<0>(&captured_nigori_state));
+      .WillOnce(testing::SaveArg<0>(&captured_nigori_specifics));
   EXPECT_CALL(*observer(), OnEncryptionComplete());
   encryption_handler()->EnableEncryptEverything();
 
@@ -1115,7 +1115,7 @@
                                         &passphrase_bootstrap_token);
   VerifyRestoreAfterExplicitPaspshrase(
       TimeToProtoTime(migration_time), kCurKey, passphrase_bootstrap_token,
-      captured_nigori_state, PassphraseType::kFrozenImplicitPassphrase,
+      captured_nigori_specifics, PassphraseType::kFrozenImplicitPassphrase,
       /*key_derivation_method=*/base::nullopt);
 }
 
@@ -1147,14 +1147,14 @@
   encryption_handler()->EnableEncryptEverything();
   Mock::VerifyAndClearExpectations(observer());
 
-  SyncEncryptionHandler::NigoriState captured_nigori_state;
+  sync_pb::NigoriSpecifics captured_nigori_specifics;
   // Once we provide a keystore key, we should perform the migration.
   EXPECT_CALL(*observer(), OnCryptographerStateChanged(_, _))
       .Times(AnyNumber());
   EXPECT_CALL(*observer(),
               OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
   EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_))
-      .WillOnce(testing::SaveArg<0>(&captured_nigori_state));
+      .WillOnce(testing::SaveArg<0>(&captured_nigori_specifics));
   encryption_handler()->SetKeystoreKeys({kRawKeystoreKey});
 
   // The actual migration gets posted, so run all pending tasks.
@@ -1171,7 +1171,7 @@
 
   VerifyRestoreAfterExplicitPaspshrase(
       TimeToProtoTime(migration_time), kCurKey, captured_bootstrap_token,
-      captured_nigori_state, PassphraseType::kCustomPassphrase,
+      captured_nigori_specifics, PassphraseType::kCustomPassphrase,
       {KeyDerivationParams::CreateForPbkdf2()});
 }
 
@@ -1206,9 +1206,9 @@
               OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
   encryption_handler()->SetKeystoreKeys({kRawKeystoreKey});
   EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, true));
-  SyncEncryptionHandler::NigoriState captured_nigori_state;
+  sync_pb::NigoriSpecifics captured_nigori_specifics;
   EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_))
-      .WillOnce(testing::SaveArg<0>(&captured_nigori_state));
+      .WillOnce(testing::SaveArg<0>(&captured_nigori_specifics));
   EXPECT_CALL(*observer(), OnEncryptionComplete());
   // The actual migration gets posted, so run all pending tasks.
   PumpLoop();
@@ -1222,7 +1222,7 @@
 
   VerifyRestoreAfterExplicitPaspshrase(
       TimeToProtoTime(migration_time), kCurKey, captured_bootstrap_token,
-      captured_nigori_state, PassphraseType::kCustomPassphrase,
+      captured_nigori_specifics, PassphraseType::kCustomPassphrase,
       {KeyDerivationParams::CreateForPbkdf2()});
 }
 
@@ -1497,9 +1497,9 @@
   // properly overwrite it with the migrated + encrypt everything state.
   EXPECT_CALL(*observer(), OnCryptographerStateChanged(_, _))
       .Times(AnyNumber());
-  SyncEncryptionHandler::NigoriState captured_nigori_state;
+  sync_pb::NigoriSpecifics captured_nigori_specifics;
   EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_))
-      .WillOnce(testing::SaveArg<0>(&captured_nigori_state));
+      .WillOnce(testing::SaveArg<0>(&captured_nigori_specifics));
   EXPECT_CALL(*observer(), OnEncryptionComplete());
   {
     DirectoryCryptographer other_cryptographer;
@@ -1533,7 +1533,7 @@
                                         &passphrase_bootstrap_token);
   VerifyRestoreAfterExplicitPaspshrase(
       migration_time, kCurKey, passphrase_bootstrap_token,
-      captured_nigori_state, PassphraseType::kCustomPassphrase,
+      captured_nigori_specifics, PassphraseType::kCustomPassphrase,
       {KeyDerivationParams::CreateForPbkdf2()});
 }
 
@@ -1588,9 +1588,9 @@
   // properly overwrite it with the migrated + encrypt everything state.
   EXPECT_CALL(*observer(), OnCryptographerStateChanged(_, _))
       .Times(AnyNumber());
-  SyncEncryptionHandler::NigoriState captured_nigori_state;
+  sync_pb::NigoriSpecifics captured_nigori_specifics;
   EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_))
-      .WillOnce(testing::SaveArg<0>(&captured_nigori_state));
+      .WillOnce(testing::SaveArg<0>(&captured_nigori_specifics));
   EXPECT_CALL(*observer(), OnEncryptionComplete());
   const int64_t migration_time = 1;
   {
@@ -1630,7 +1630,7 @@
                                         &passphrase_bootstrap_token);
   VerifyRestoreAfterExplicitPaspshrase(
       migration_time, kCurKey, passphrase_bootstrap_token,
-      captured_nigori_state, PassphraseType::kCustomPassphrase,
+      captured_nigori_specifics, PassphraseType::kCustomPassphrase,
       {KeyDerivationParams::CreateForPbkdf2()});
 }
 
@@ -1771,9 +1771,9 @@
       .Times(AnyNumber());
   EXPECT_CALL(*observer(),
               OnPassphraseTypeChanged(PassphraseType::kCustomPassphrase, _));
-  SyncEncryptionHandler::NigoriState captured_nigori_state;
+  sync_pb::NigoriSpecifics captured_nigori_specifics;
   EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_))
-      .WillOnce(testing::SaveArg<0>(&captured_nigori_state));
+      .WillOnce(testing::SaveArg<0>(&captured_nigori_specifics));
   std::string captured_bootstrap_token;
   EXPECT_CALL(*observer(),
               OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN))
@@ -1820,8 +1820,8 @@
   // Now verify that we can restore the current state using the captured
   // bootstrap token and nigori state.
   VerifyRestoreAfterExplicitPaspshrase(
-      migration_time, kNewKey, captured_bootstrap_token, captured_nigori_state,
-      PassphraseType::kCustomPassphrase,
+      migration_time, kNewKey, captured_bootstrap_token,
+      captured_nigori_specifics, PassphraseType::kCustomPassphrase,
       {KeyDerivationParams::CreateForScrypt(kScryptSalt)});
 }
 
@@ -1890,9 +1890,9 @@
       .Times(AnyNumber());
   EXPECT_CALL(*observer(),
               OnPassphraseTypeChanged(PassphraseType::kCustomPassphrase, _));
-  SyncEncryptionHandler::NigoriState captured_nigori_state;
+  sync_pb::NigoriSpecifics captured_nigori_specifics;
   EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_))
-      .WillOnce(testing::SaveArg<0>(&captured_nigori_state));
+      .WillOnce(testing::SaveArg<0>(&captured_nigori_specifics));
   std::string captured_bootstrap_token;
   EXPECT_CALL(*observer(),
               OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN))
@@ -1935,8 +1935,8 @@
   // Now verify that we can restore the current state using the captured
   // bootstrap token and nigori state.
   VerifyRestoreAfterExplicitPaspshrase(
-      migration_time, kNewKey, captured_bootstrap_token, captured_nigori_state,
-      PassphraseType::kCustomPassphrase,
+      migration_time, kNewKey, captured_bootstrap_token,
+      captured_nigori_specifics, PassphraseType::kCustomPassphrase,
       {KeyDerivationParams::CreateForScrypt(kScryptSalt)});
 }
 
@@ -2003,9 +2003,9 @@
                                PassphraseType::kFrozenImplicitPassphrase, _));
   EXPECT_CALL(*observer(), OnEncryptionComplete());
   EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, true));
-  SyncEncryptionHandler::NigoriState captured_nigori_state;
+  sync_pb::NigoriSpecifics captured_nigori_specifics;
   EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_))
-      .WillOnce(testing::SaveArg<0>(&captured_nigori_state));
+      .WillOnce(testing::SaveArg<0>(&captured_nigori_specifics));
   EXPECT_CALL(*observer(), OnCryptographerStateChanged(_, _))
       .Times(AnyNumber());
   encryption_handler()->EnableEncryptEverything();
@@ -2033,8 +2033,8 @@
   EXPECT_TRUE(GetCryptographer()->CanDecrypt(keystore_encrypted));
 
   VerifyRestoreAfterExplicitPaspshrase(
-      migration_time, kCurKey, captured_bootstrap_token, captured_nigori_state,
-      PassphraseType::kFrozenImplicitPassphrase,
+      migration_time, kCurKey, captured_bootstrap_token,
+      captured_nigori_specifics, PassphraseType::kFrozenImplicitPassphrase,
       /*key_derivation_method=*/base::nullopt);
 }
 
@@ -2313,9 +2313,9 @@
       .Times(AnyNumber());
   EXPECT_CALL(*observer(), OnPassphraseAccepted());
   EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, true));
-  SyncEncryptionHandler::NigoriState captured_nigori_state;
+  sync_pb::NigoriSpecifics captured_nigori_specifics;
   EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_))
-      .WillOnce(testing::SaveArg<0>(&captured_nigori_state));
+      .WillOnce(testing::SaveArg<0>(&captured_nigori_specifics));
   EXPECT_CALL(*observer(), OnEncryptionComplete()).Times(AnyNumber());
   std::string captured_bootstrap_token;
   EXPECT_CALL(*observer(),
@@ -2331,7 +2331,7 @@
       encryption_handler()->GetKeystoreMigrationTime();
   VerifyRestoreAfterExplicitPaspshrase(
       TimeToProtoTime(migration_time), kCustomPass, captured_bootstrap_token,
-      captured_nigori_state, PassphraseType::kCustomPassphrase,
+      captured_nigori_specifics, PassphraseType::kCustomPassphrase,
       {KeyDerivationParams::CreateForPbkdf2()});
 }
 
@@ -2352,14 +2352,14 @@
       migration_time, PassphraseType::kCustomPassphrase, kCustomPass,
       {KeyDerivationParams::CreateForPbkdf2()});
 
-  SyncEncryptionHandler::NigoriState captured_nigori_state;
+  sync_pb::NigoriSpecifics captured_nigori_specifics;
   // Pass multiple keystore keys, signaling a rotation has happened.
   EXPECT_CALL(*observer(),
               OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
   EXPECT_CALL(*observer(), OnCryptographerStateChanged(_, _))
       .Times(AnyNumber());
   EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_))
-      .WillOnce(testing::SaveArg<0>(&captured_nigori_state));
+      .WillOnce(testing::SaveArg<0>(&captured_nigori_specifics));
   encryption_handler()->SetKeystoreKeys({kRawOldKeystoreKey, kRawKeystoreKey});
 
   PumpLoop();
@@ -2377,7 +2377,7 @@
                                         &passphrase_bootstrap_token);
   VerifyRestoreAfterExplicitPaspshrase(
       migration_time, kCustomPass, passphrase_bootstrap_token,
-      captured_nigori_state, PassphraseType::kCustomPassphrase,
+      captured_nigori_specifics, PassphraseType::kCustomPassphrase,
       {KeyDerivationParams::CreateForPbkdf2()});
 }
 
diff --git a/components/sync/engine_impl/sync_manager_impl_unittest.cc b/components/sync/engine_impl/sync_manager_impl_unittest.cc
index d1acbc2..0daef38 100644
--- a/components/sync/engine_impl/sync_manager_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_manager_impl_unittest.cc
@@ -923,7 +923,7 @@
                void(PassphraseType,
                     base::Time));  // NOLINT
   MOCK_METHOD1(OnLocalSetPassphraseEncryption,
-               void(const SyncEncryptionHandler::NigoriState&));  // NOLINT
+               void(const sync_pb::NigoriSpecifics&));
 };
 
 }  // namespace
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.cc b/components/sync/nigori/nigori_sync_bridge_impl.cc
index 9ef3de9..d10555b 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl.cc
+++ b/components/sync/nigori/nigori_sync_bridge_impl.cc
@@ -744,6 +744,14 @@
   return this;
 }
 
+std::string NigoriSyncBridgeImpl::GetLastKeystoreKey() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (state_.keystore_keys.empty()) {
+    return std::string();
+  }
+  return state_.keystore_keys.back();
+}
+
 bool NigoriSyncBridgeImpl::NeedKeystoreKey() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // We explicitly ask the server for keystore keys iff it's first-time sync,
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.h b/components/sync/nigori/nigori_sync_bridge_impl.h
index 6523d52..cc3a8c2 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl.h
+++ b/components/sync/nigori/nigori_sync_bridge_impl.h
@@ -66,6 +66,7 @@
   bool IsEncryptEverythingEnabled() const override;
   base::Time GetKeystoreMigrationTime() const override;
   KeystoreKeysHandler* GetKeystoreKeysHandler() override;
+  std::string GetLastKeystoreKey() const override;
 
   // KeystoreKeysHandler implementation.
   bool NeedKeystoreKey() const override;
diff --git a/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc b/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
index c2e72b2..1c447336 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
+++ b/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
@@ -318,7 +318,7 @@
                void(Cryptographer*, bool has_pending_keys));
   MOCK_METHOD2(OnPassphraseTypeChanged, void(PassphraseType, base::Time));
   MOCK_METHOD1(OnLocalSetPassphraseEncryption,
-               void(const SyncEncryptionHandler::NigoriState&));
+               void(const sync_pb::NigoriSpecifics&));
 };
 
 class MockNigoriStorage : public NigoriStorage {
diff --git a/components/sync/syncable/model_neutral_mutable_entry.cc b/components/sync/syncable/model_neutral_mutable_entry.cc
index 808f65b..784b5232 100644
--- a/components/sync/syncable/model_neutral_mutable_entry.cc
+++ b/components/sync/syncable/model_neutral_mutable_entry.cc
@@ -51,7 +51,8 @@
                                                    ModelType type)
     : Entry(trans), base_write_transaction_(trans) {
   // We allow NIGORI because we allow SyncEncryptionHandler to restore a nigori
-  // across Directory instances (see SyncEncryptionHandler::RestoreNigori).
+  // across Directory instances (see
+  // SyncEncryptionHandler::RestoreNigoriForTesting()).
   if (type != NIGORI)
     DCHECK(IsTypeWithClientGeneratedRoot(type));
   Entry same_type_root(trans, GET_TYPE_ROOT, type);
diff --git a/components/sync/test/fake_sync_encryption_handler.cc b/components/sync/test/fake_sync_encryption_handler.cc
index e250953..8bf8d20 100644
--- a/components/sync/test/fake_sync_encryption_handler.cc
+++ b/components/sync/test/fake_sync_encryption_handler.cc
@@ -150,6 +150,10 @@
   return this;
 }
 
+std::string FakeSyncEncryptionHandler::GetLastKeystoreKey() const {
+  return std::string();
+}
+
 DirectoryCryptographer* FakeSyncEncryptionHandler::GetMutableCryptographer() {
   return &cryptographer_;
 }
diff --git a/components/sync/test/fake_sync_encryption_handler.h b/components/sync/test/fake_sync_encryption_handler.h
index a2958af..b48a3ac 100644
--- a/components/sync/test/fake_sync_encryption_handler.h
+++ b/components/sync/test/fake_sync_encryption_handler.h
@@ -43,6 +43,7 @@
   bool IsEncryptEverythingEnabled() const override;
   base::Time GetKeystoreMigrationTime() const override;
   KeystoreKeysHandler* GetKeystoreKeysHandler() override;
+  std::string GetLastKeystoreKey() const override;
 
   // NigoriHandler implemenation.
   bool ApplyNigoriUpdate(const sync_pb::NigoriSpecifics& nigori,
diff --git a/components/sync_device_info/device_info_sync_bridge.cc b/components/sync_device_info/device_info_sync_bridge.cc
index b818707..6caa11c 100644
--- a/components/sync_device_info/device_info_sync_bridge.cc
+++ b/components/sync_device_info/device_info_sync_bridge.cc
@@ -202,6 +202,8 @@
   device_info_prefs_->GarbageCollectExpiredCacheGuids();
   // Add the cache guid to the local prefs.
   device_info_prefs_->AddLocalCacheGuid(local_cache_guid_);
+  // SyncMode determines the client name in GetLocalClientName().
+  sync_mode_ = request.sync_mode;
 }
 
 std::unique_ptr<MetadataChangeList>
@@ -216,9 +218,8 @@
   DCHECK(all_data_.empty());
   DCHECK(!local_cache_guid_.empty());
 
-  local_device_info_provider_->Initialize(local_cache_guid_,
-                                          local_personalizable_device_name_,
-                                          local_hardware_info_);
+  local_device_info_provider_->Initialize(
+      local_cache_guid_, GetLocalClientName(), local_hardware_info_);
 
   std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch();
   for (const auto& change : entity_data) {
@@ -397,6 +398,22 @@
   }
 }
 
+std::string DeviceInfoSyncBridge::GetLocalClientName() const {
+  // |sync_mode_| may not be ready when this function is called.
+  if (!sync_mode_) {
+    auto device_it = all_data_.find(local_cache_guid_);
+    if (device_it != all_data_.end()) {
+      return device_it->second->client_name();
+    }
+  }
+
+  if (sync_mode_ == SyncMode::kFull) {
+    return local_personalizable_device_name_;
+  }
+
+  return local_hardware_info_.model;
+}
+
 void DeviceInfoSyncBridge::OnStoreCreated(
     const base::Optional<syncer::ModelError>& error,
     std::unique_ptr<ModelTypeStore> store) {
@@ -498,9 +515,8 @@
   // If sync already enabled (usual case without data corruption), we can
   // initialize the provider immediately.
   local_cache_guid_ = local_cache_guid_in_metadata;
-  local_device_info_provider_->Initialize(local_cache_guid_,
-                                          local_personalizable_device_name_,
-                                          local_hardware_info_);
+  local_device_info_provider_->Initialize(
+      local_cache_guid_, GetLocalClientName(), local_hardware_info_);
 
   // This probably isn't strictly needed, but in case the cache_guid has changed
   // we save the new one to prefs.
diff --git a/components/sync_device_info/device_info_sync_bridge.h b/components/sync_device_info/device_info_sync_bridge.h
index 1e7fb12..1a2b3836 100644
--- a/components/sync_device_info/device_info_sync_bridge.h
+++ b/components/sync_device_info/device_info_sync_bridge.h
@@ -17,6 +17,7 @@
 #include "base/system/sys_info.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+#include "components/sync/base/sync_mode.h"
 #include "components/sync/model/model_error.h"
 #include "components/sync/model/model_type_store.h"
 #include "components/sync/model/model_type_sync_bridge.h"
@@ -96,6 +97,11 @@
   bool DeleteSpecifics(const std::string& tag,
                        ModelTypeStore::WriteBatch* batch);
 
+  // Returns the device name based on |sync_mode_|. For transport only mode,
+  // the device model name is returned. For full sync mode,
+  // |local_personalizable_device_name_| is returned.
+  std::string GetLocalClientName() const;
+
   // Notify all registered observers.
   void NotifyObservers();
 
@@ -145,6 +151,7 @@
   std::string local_personalizable_device_name_;
   ClientIdToSpecifics all_data_;
   base::SysInfo::HardwareInfo local_hardware_info_;
+  base::Optional<SyncMode> sync_mode_;
 
   // Registered observers, not owned.
   base::ObserverList<Observer, true>::Unchecked observers_;
diff --git a/components/sync_device_info/device_info_sync_bridge_unittest.cc b/components/sync_device_info/device_info_sync_bridge_unittest.cc
index 1cb0031b..4c2186f 100644
--- a/components/sync_device_info/device_info_sync_bridge_unittest.cc
+++ b/components/sync_device_info/device_info_sync_bridge_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/simple_test_clock.h"
 #include "base/test/task_environment.h"
 #include "components/prefs/testing_pref_service.h"
@@ -25,6 +26,7 @@
 #include "components/sync/protocol/model_type_state.pb.h"
 #include "components/sync/test/test_matchers.h"
 #include "components/sync_device_info/device_info_prefs.h"
+#include "components/sync_device_info/local_device_info_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace syncer {
@@ -140,6 +142,18 @@
   return base::StringPrintf("signin scoped device id %d", suffix);
 }
 
+base::SysInfo::HardwareInfo GetLocalHardwareInfoBlocking() {
+  base::RunLoop run_loop;
+  base::SysInfo::HardwareInfo info;
+  base::SysInfo::GetHardwareInfo(base::BindLambdaForTesting(
+      [&](base::SysInfo::HardwareInfo hardware_info) {
+        info = std::move(hardware_info);
+        run_loop.Quit();
+      }));
+  run_loop.Run();
+  return info;
+}
+
 std::string ModelForSuffix(int suffix) {
   return base::StringPrintf("model %d", suffix);
 }
@@ -148,13 +162,6 @@
   return base::StringPrintf("manufacturer %d", suffix);
 }
 
-base::SysInfo::HardwareInfo HardwareInfoForSuffix(int suffix) {
-  base::SysInfo::HardwareInfo info;
-  info.manufacturer = ManufacturerForSuffix(suffix);
-  info.model = ModelForSuffix(suffix);
-  return info;
-}
-
 std::string SharingFcmTokenForSuffix(int suffix) {
   return base::StringPrintf("sharing fcm token %d", suffix);
 }
@@ -173,9 +180,10 @@
                     : sync_pb::SharingSpecificFields::SHARED_CLIPBOARD;
 }
 
-DataTypeActivationRequest TestDataTypeActivationRequest() {
+DataTypeActivationRequest TestDataTypeActivationRequest(SyncMode sync_mode) {
   DataTypeActivationRequest request;
   request.cache_guid = CacheGuidForSuffix(kLocalSuffix);
+  request.sync_mode = sync_mode;
   return request;
 }
 
@@ -205,6 +213,41 @@
   return specifics;
 }
 
+DeviceInfoSpecifics DeviceInfoToSpecifics(const DeviceInfo& info) {
+  auto hardware_info = info.hardware_info();
+  DeviceInfoSpecifics specifics;
+  specifics.set_cache_guid(info.guid());
+  specifics.set_client_name(info.client_name());
+  specifics.set_chrome_version(info.chrome_version());
+  specifics.set_sync_user_agent(info.sync_user_agent());
+  specifics.set_device_type(info.device_type());
+  specifics.set_signin_scoped_device_id(info.signin_scoped_device_id());
+  specifics.set_model(hardware_info.model);
+  specifics.set_manufacturer(hardware_info.manufacturer);
+  specifics.set_last_updated_timestamp(TimeToProtoTime(base::Time::Now()));
+
+  sync_pb::FeatureSpecificFields* feature_fields =
+      specifics.mutable_feature_fields();
+  feature_fields->set_send_tab_to_self_receiving_enabled(
+      info.send_tab_to_self_receiving_enabled());
+
+  const base::Optional<DeviceInfo::SharingInfo>& sharing_info =
+      info.sharing_info();
+  if (sharing_info) {
+    sync_pb::SharingSpecificFields* sharing_fields =
+        specifics.mutable_sharing_fields();
+    sharing_fields->set_fcm_token(sharing_info->fcm_token);
+    sharing_fields->set_p256dh(sharing_info->p256dh);
+    sharing_fields->set_auth_secret(sharing_info->auth_secret);
+    for (sync_pb::SharingSpecificFields::EnabledFeatures feature :
+         sharing_info->enabled_features) {
+      sharing_fields->add_enabled_features(feature);
+    }
+  }
+
+  return specifics;
+}
+
 ModelTypeState StateWithEncryption(const std::string& encryption_key_name) {
   ModelTypeState state;
   state.set_initial_sync_done(true);
@@ -254,9 +297,6 @@
   ~TestLocalDeviceInfoProvider() override = default;
 
   // MutableLocalDeviceInfoProvider implementation.
-  // TODO(himanshujaju) - |hardware_info| is ignored right now. We could reuse
-  // it by calling GetHardwareInfo and storing locally before starting the
-  // tests.
   void Initialize(const std::string& cache_guid,
                   const std::string& session_name,
                   const base::SysInfo::HardwareInfo& hardware_info) override {
@@ -266,8 +306,8 @@
         cache_guid, session_name, ChromeVersionForSuffix(kLocalSuffix),
         SyncUserAgentForSuffix(kLocalSuffix),
         sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
-        SigninScopedDeviceIdForSuffix(kLocalSuffix),
-        HardwareInfoForSuffix(kLocalSuffix), base::Time(),
+        SigninScopedDeviceIdForSuffix(kLocalSuffix), hardware_info,
+        base::Time(),
         /*send_tab_to_self_receiving_enabled=*/true,
         DeviceInfo::SharingInfo(SharingFcmTokenForSuffix(kLocalSuffix),
                                 SharingP256dhForSuffix(kLocalSuffix),
@@ -301,7 +341,8 @@
                                  public DeviceInfoTracker::Observer {
  protected:
   DeviceInfoSyncBridgeTest()
-      : store_(ModelTypeStoreTestUtil::CreateInMemoryStoreForTest()) {
+      : store_(ModelTypeStoreTestUtil::CreateInMemoryStoreForTest()),
+        local_hardware_info_(GetLocalHardwareInfoBlocking()) {
     DeviceInfoPrefs::RegisterProfilePrefs(pref_service_.registry());
     ON_CALL(*processor(), IsTrackingMetadata()).WillByDefault(Return(true));
   }
@@ -315,6 +356,14 @@
     base::RunLoop().RunUntilIdle();
   }
 
+  DeviceInfoSpecifics CreateLocalDeviceSpecifics(
+      const base::Time last_updated = base::Time::Now()) {
+    DeviceInfoSpecifics specifics = CreateSpecifics(kLocalSuffix, last_updated);
+    specifics.set_model(local_hardware_info_.model);
+    specifics.set_manufacturer(local_hardware_info_.manufacturer);
+    return specifics;
+  }
+
   void OnDeviceInfoChange() override { change_count_++; }
 
   // Initialized the bridge based on the current local device and store.
@@ -336,9 +385,9 @@
 
   // Creates the bridge with no prior data on the store, and mimics sync being
   // enabled by the user with no remote data.
-  void InitializeAndMergeInitialData() {
+  void InitializeAndMergeInitialData(SyncMode sync_mode) {
     InitializeAndPump();
-    bridge()->OnSyncStarting(TestDataTypeActivationRequest());
+    bridge()->OnSyncStarting(TestDataTypeActivationRequest(sync_mode));
 
     std::unique_ptr<MetadataChangeList> metadata_change_list =
         bridge()->CreateMetadataChangeList();
@@ -490,6 +539,9 @@
   // Holds the store.
   const std::unique_ptr<ModelTypeStore> store_;
 
+  // Stores the local device's hardware information.
+  const base::SysInfo::HardwareInfo local_hardware_info_;
+
   TestingPrefServiceSimple pref_service_;
   // Not initialized immediately (upon test's constructor). This allows each
   // test case to modify the dependencies the bridge will be constructed with.
@@ -543,7 +595,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, TestWithLocalDataAndMetadata) {
-  const DeviceInfoSpecifics local_specifics = CreateSpecifics(kLocalSuffix);
+  const DeviceInfoSpecifics local_specifics = CreateLocalDeviceSpecifics();
   ModelTypeState state = StateWithEncryption("ekn");
   WriteToStoreWithMetadata({local_specifics}, state);
 
@@ -559,7 +611,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, TestWithMultipleLocalDataAndMetadata) {
-  const DeviceInfoSpecifics local_specifics = CreateSpecifics(kLocalSuffix);
+  const DeviceInfoSpecifics local_specifics = CreateLocalDeviceSpecifics();
   const DeviceInfoSpecifics remote_specifics = CreateSpecifics(1);
   ModelTypeState state = StateWithEncryption("ekn");
   WriteToStoreWithMetadata({local_specifics, remote_specifics}, state);
@@ -577,7 +629,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, GetData) {
-  const DeviceInfoSpecifics local_specifics = CreateSpecifics(kLocalSuffix);
+  const DeviceInfoSpecifics local_specifics = CreateLocalDeviceSpecifics();
   const DeviceInfoSpecifics specifics1 = CreateSpecifics(1);
   const DeviceInfoSpecifics specifics2 = CreateSpecifics(2);
   const DeviceInfoSpecifics specifics3 = CreateSpecifics(3);
@@ -609,7 +661,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, GetAllData) {
-  const DeviceInfoSpecifics local_specifics = CreateSpecifics(kLocalSuffix);
+  const DeviceInfoSpecifics local_specifics = CreateLocalDeviceSpecifics();
   const DeviceInfoSpecifics specifics1 = CreateSpecifics(1);
   const DeviceInfoSpecifics specifics2 = CreateSpecifics(2);
   WriteToStoreWithMetadata({local_specifics, specifics1, specifics2},
@@ -624,7 +676,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, ApplySyncChangesEmpty) {
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   ASSERT_EQ(1, change_count());
 
   auto error = bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(),
@@ -634,7 +686,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, ApplySyncChangesInMemory) {
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   ASSERT_EQ(1, change_count());
 
   const DeviceInfoSpecifics specifics = CreateSpecifics(1);
@@ -660,7 +712,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, ApplySyncChangesStore) {
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   ASSERT_EQ(1, change_count());
 
   const DeviceInfoSpecifics specifics = CreateSpecifics(1);
@@ -686,7 +738,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, ApplySyncChangesWithLocalGuid) {
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   ASSERT_EQ(1, change_count());
 
   ASSERT_TRUE(
@@ -697,7 +749,7 @@
   // guid will match the local device.
   EXPECT_CALL(*processor(), Put(_, _, _)).Times(0);
 
-  const DeviceInfoSpecifics specifics = CreateSpecifics(kLocalSuffix);
+  const DeviceInfoSpecifics specifics = CreateLocalDeviceSpecifics();
   auto error_on_add = bridge()->ApplySyncChanges(
       bridge()->CreateMetadataChangeList(), EntityAddList({specifics}));
   EXPECT_FALSE(error_on_add);
@@ -713,7 +765,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, ApplyDeleteNonexistent) {
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   ASSERT_EQ(1, change_count());
 
   syncer::EntityChangeList entity_change_list;
@@ -736,7 +788,7 @@
   EXPECT_CALL(*processor(), Put(kLocalGuid, _, _));
   EXPECT_CALL(*processor(), Delete(_, _)).Times(0);
 
-  bridge()->OnSyncStarting(TestDataTypeActivationRequest());
+  bridge()->OnSyncStarting(TestDataTypeActivationRequest(SyncMode::kFull));
   auto error = bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(),
                                        EntityChangeList());
   EXPECT_FALSE(error);
@@ -757,10 +809,10 @@
   EXPECT_CALL(*processor(), Put(kLocalGuid, _, _));
   EXPECT_CALL(*processor(), Delete(_, _)).Times(0);
 
-  bridge()->OnSyncStarting(TestDataTypeActivationRequest());
+  bridge()->OnSyncStarting(TestDataTypeActivationRequest(SyncMode::kFull));
   auto error =
       bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(),
-                              EntityAddList({CreateSpecifics(kLocalSuffix)}));
+                              EntityAddList({CreateLocalDeviceSpecifics()}));
 
   EXPECT_FALSE(error);
   EXPECT_EQ(1, change_count());
@@ -770,7 +822,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, CountActiveDevices) {
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   // Local device.
   EXPECT_EQ(1, bridge()->CountActiveDevices());
 
@@ -782,11 +834,11 @@
   // Regardless of the time, these following two ApplySyncChanges(...) calls
   // have the same guid as the local device.
   bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(),
-                             EntityAddList({CreateSpecifics(kLocalSuffix)}));
+                             EntityAddList({CreateLocalDeviceSpecifics()}));
   EXPECT_EQ(1, bridge()->CountActiveDevices());
 
   bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(),
-                             EntityAddList({CreateSpecifics(kLocalSuffix)}));
+                             EntityAddList({CreateLocalDeviceSpecifics()}));
   EXPECT_EQ(1, bridge()->CountActiveDevices());
 
   // A different guid will actually contribute to the count.
@@ -803,7 +855,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, CountActiveDevicesWithOverlappingTime) {
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   // Local device.
   ASSERT_EQ(1, bridge()->CountActiveDevices());
 
@@ -848,7 +900,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, CountActiveDevicesWithNonOverlappingTime) {
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   // Local device.
   ASSERT_EQ(1, bridge()->CountActiveDevices());
 
@@ -886,7 +938,7 @@
 
 TEST_F(DeviceInfoSyncBridgeTest,
        CountActiveDevicesWithNonOverlappingTimeAndDistictType) {
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   // Local device.
   ASSERT_EQ(1, bridge()->CountActiveDevices());
 
@@ -928,7 +980,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, CountActiveDevicesWithMalformedTimestamps) {
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   // Local device.
   ASSERT_EQ(1, bridge()->CountActiveDevices());
 
@@ -960,7 +1012,7 @@
 TEST_F(DeviceInfoSyncBridgeTest, SendLocalData) {
   // Ensure |last_updated| is about now, plus or minus a little bit.
   EXPECT_CALL(*processor(), Put(_, HasSpecifics(HasLastUpdatedAboutNow()), _));
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   EXPECT_EQ(1, change_count());
   testing::Mock::VerifyAndClearExpectations(processor());
 
@@ -971,7 +1023,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, ApplyStopSyncChangesWithClearData) {
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   ASSERT_EQ(1u, bridge()->GetAllDeviceInfo().size());
   ASSERT_EQ(1, change_count());
   ASSERT_FALSE(ReadAllFromStore().empty());
@@ -998,7 +1050,7 @@
 
   // If sync is re-enabled and the remote data is now empty, we shouldn't
   // contain remote data.
-  bridge()->OnSyncStarting(TestDataTypeActivationRequest());
+  bridge()->OnSyncStarting(TestDataTypeActivationRequest(SyncMode::kFull));
   bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(),
                           EntityChangeList());
   // Local device.
@@ -1007,7 +1059,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, ApplyStopSyncChangesWithKeepData) {
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   ASSERT_EQ(1u, bridge()->GetAllDeviceInfo().size());
   ASSERT_EQ(1, change_count());
   ASSERT_FALSE(ReadAllFromStore().empty());
@@ -1035,7 +1087,7 @@
 }
 
 TEST_F(DeviceInfoSyncBridgeTest, ExpireOldEntriesUponStartup) {
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   ASSERT_EQ(1u, bridge()->GetAllDeviceInfo().size());
   ASSERT_EQ(1, change_count());
   ASSERT_FALSE(ReadAllFromStore().empty());
@@ -1066,7 +1118,7 @@
 TEST_F(DeviceInfoSyncBridgeTest, RefreshLocalDeviceInfo) {
   // Ensure |last_updated| is about now, plus or minus a little bit.
   EXPECT_CALL(*processor(), Put(_, HasSpecifics(HasLastUpdatedAboutNow()), _));
-  InitializeAndMergeInitialData();
+  InitializeAndMergeInitialData(SyncMode::kFull);
   EXPECT_EQ(1, change_count());
   testing::Mock::VerifyAndClearExpectations(processor());
 
@@ -1076,6 +1128,105 @@
   EXPECT_EQ(2, change_count());
 }
 
+TEST_F(DeviceInfoSyncBridgeTest, DeviceNameForTransportOnlySyncMode) {
+  InitializeAndMergeInitialData(SyncMode::kTransportOnly);
+  ASSERT_EQ(1, change_count());
+  ASSERT_TRUE(local_device()->GetLocalDeviceInfo());
+
+  EXPECT_EQ(GetLocalHardwareInfoBlocking().model,
+            local_device()->GetLocalDeviceInfo()->client_name());
+}
+
+TEST_F(DeviceInfoSyncBridgeTest, DeviceNameForFullSyncMode) {
+  InitializeAndMergeInitialData(SyncMode::kFull);
+  ASSERT_EQ(1, change_count());
+  ASSERT_TRUE(local_device()->GetLocalDeviceInfo());
+
+  EXPECT_EQ(GetPersonalizableDeviceNameBlocking(),
+            local_device()->GetLocalDeviceInfo()->client_name());
+}
+
+// Tests local client name when device is initially synced with transport only
+// sync mode, but the sync mode is not available after restart since it is not
+// persisted.
+TEST_F(DeviceInfoSyncBridgeTest,
+       DeviceNameForTransportOnlySyncMode_RestartBridge) {
+  std::string expected_device_name = GetLocalHardwareInfoBlocking().model;
+  InitializeAndMergeInitialData(SyncMode::kTransportOnly);
+
+  ASSERT_TRUE(local_device()->GetLocalDeviceInfo());
+  ASSERT_EQ(expected_device_name,
+            local_device()->GetLocalDeviceInfo()->client_name());
+
+  EXPECT_CALL(*processor(),
+              Put(local_device()->GetLocalDeviceInfo()->guid(), _, _))
+      .Times(0);
+  RestartBridge();
+  ASSERT_TRUE(local_device()->GetLocalDeviceInfo());
+  EXPECT_EQ(expected_device_name,
+            local_device()->GetLocalDeviceInfo()->client_name());
+}
+
+// Tests local client name when device is initially synced with full sync mode,
+// but the sync mode is not available after restart since it is not persisted.
+TEST_F(DeviceInfoSyncBridgeTest, DeviceNameForFullSyncMode_RestartBridge) {
+  std::string expected_device_name = GetPersonalizableDeviceNameBlocking();
+  InitializeAndMergeInitialData(SyncMode::kFull);
+
+  ASSERT_TRUE(local_device()->GetLocalDeviceInfo());
+  ASSERT_EQ(expected_device_name,
+            local_device()->GetLocalDeviceInfo()->client_name());
+
+  EXPECT_CALL(*processor(),
+              Put(local_device()->GetLocalDeviceInfo()->guid(), _, _))
+      .Times(0);
+  RestartBridge();
+  ASSERT_TRUE(local_device()->GetLocalDeviceInfo());
+  EXPECT_EQ(expected_device_name,
+            local_device()->GetLocalDeviceInfo()->client_name());
+}
+
+TEST_F(DeviceInfoSyncBridgeTest, RefreshLocalDeviceNameForSyncModeToggle) {
+  std::string expected_device_name_full_sync =
+      GetPersonalizableDeviceNameBlocking();
+  std::string expected_device_name_transport_only =
+      GetLocalHardwareInfoBlocking().model;
+
+  // Initialize with full sync mode.
+  InitializeAndMergeInitialData(SyncMode::kFull);
+  const syncer::DeviceInfo* device = local_device()->GetLocalDeviceInfo();
+
+  ASSERT_TRUE(device);
+  ASSERT_EQ(expected_device_name_full_sync, device->client_name());
+
+  // Toggle to transport only sync mode.
+  syncer::EntityChangeList entity_change_list;
+  entity_change_list.push_back(EntityChange::CreateUpdate(
+      device->guid(), SpecificsToEntity(DeviceInfoToSpecifics(*device))));
+  bridge()->ApplyStopSyncChanges(bridge()->CreateMetadataChangeList());
+  bridge()->OnSyncStarting(
+      TestDataTypeActivationRequest(SyncMode::kTransportOnly));
+  bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(),
+                          std::move(entity_change_list));
+
+  device = local_device()->GetLocalDeviceInfo();
+  ASSERT_TRUE(device);
+  ASSERT_EQ(expected_device_name_transport_only, device->client_name());
+
+  // Toggle to full sync mode.
+  ASSERT_TRUE(entity_change_list.empty());
+  entity_change_list.push_back(EntityChange::CreateUpdate(
+      device->guid(), SpecificsToEntity(DeviceInfoToSpecifics(*device))));
+  bridge()->ApplyStopSyncChanges(bridge()->CreateMetadataChangeList());
+  bridge()->OnSyncStarting(TestDataTypeActivationRequest(SyncMode::kFull));
+  bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(),
+                          std::move(entity_change_list));
+
+  device = local_device()->GetLocalDeviceInfo();
+  ASSERT_TRUE(device);
+  ASSERT_EQ(expected_device_name_full_sync, device->client_name());
+}
+
 }  // namespace
 
 }  // namespace syncer
diff --git a/components/sync_device_info/local_device_info_provider.h b/components/sync_device_info/local_device_info_provider.h
index 1a6c368..cb502af 100644
--- a/components/sync_device_info/local_device_info_provider.h
+++ b/components/sync_device_info/local_device_info_provider.h
@@ -43,7 +43,7 @@
 class MutableLocalDeviceInfoProvider : public LocalDeviceInfoProvider {
  public:
   virtual void Initialize(const std::string& cache_guid,
-                          const std::string& session_name,
+                          const std::string& client_name,
                           const base::SysInfo::HardwareInfo& hardware_info) = 0;
   virtual void Clear() = 0;
 };
diff --git a/components/sync_device_info/local_device_info_provider_impl.cc b/components/sync_device_info/local_device_info_provider_impl.cc
index a353a4e..0eb7303 100644
--- a/components/sync_device_info/local_device_info_provider_impl.cc
+++ b/components/sync_device_info/local_device_info_provider_impl.cc
@@ -52,7 +52,7 @@
 
 void LocalDeviceInfoProviderImpl::Initialize(
     const std::string& cache_guid,
-    const std::string& session_name,
+    const std::string& client_name,
     const base::SysInfo::HardwareInfo& hardware_info) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!cache_guid.empty());
@@ -60,7 +60,7 @@
   // The local device doesn't have a last updated timestamps. It will be set in
   // the specifics when it will be synced up.
   local_device_info_ = std::make_unique<DeviceInfo>(
-      cache_guid, session_name, version_, MakeUserAgentForSync(channel_),
+      cache_guid, client_name, version_, MakeUserAgentForSync(channel_),
       GetLocalDeviceType(), sync_client_->GetSigninScopedDeviceId(),
       hardware_info,
       /*last_updated_timestamp=*/base::Time(),
diff --git a/components/sync_device_info/local_device_info_provider_impl.h b/components/sync_device_info/local_device_info_provider_impl.h
index fc7a0a4..63792c7e 100644
--- a/components/sync_device_info/local_device_info_provider_impl.h
+++ b/components/sync_device_info/local_device_info_provider_impl.h
@@ -30,7 +30,7 @@
 
   // MutableLocalDeviceInfoProvider implementation.
   void Initialize(const std::string& cache_guid,
-                  const std::string& session_name,
+                  const std::string& client_name,
                   const base::SysInfo::HardwareInfo& hardware_info) override;
   void Clear() override;
   version_info::Channel GetChannel() const override;
diff --git a/components/sync_device_info/local_device_info_provider_impl_unittest.cc b/components/sync_device_info/local_device_info_provider_impl_unittest.cc
index 5b83650..fd481fc8 100644
--- a/components/sync_device_info/local_device_info_provider_impl_unittest.cc
+++ b/components/sync_device_info/local_device_info_provider_impl_unittest.cc
@@ -15,7 +15,7 @@
 namespace {
 
 const char kLocalDeviceGuid[] = "foo";
-const char kLocalDeviceSessionName[] = "bar";
+const char kLocalDeviceClientName[] = "bar";
 
 const char kSharingFCMToken[] = "test_fcm_token";
 const char kSharingP256dh[] = "test_p256_dh";
@@ -58,7 +58,7 @@
   void InitializeProvider() { InitializeProvider(kLocalDeviceGuid); }
 
   void InitializeProvider(const std::string& guid) {
-    provider_->Initialize(guid, kLocalDeviceSessionName,
+    provider_->Initialize(guid, kLocalDeviceClientName,
                           base::SysInfo::HardwareInfo());
   }
 
@@ -74,7 +74,7 @@
   const DeviceInfo* local_device_info = provider_->GetLocalDeviceInfo();
   ASSERT_NE(nullptr, local_device_info);
   EXPECT_EQ(std::string(kLocalDeviceGuid), local_device_info->guid());
-  EXPECT_EQ(kLocalDeviceSessionName, local_device_info->client_name());
+  EXPECT_EQ(kLocalDeviceClientName, local_device_info->client_name());
   EXPECT_EQ(MakeUserAgentForSync(provider_->GetChannel()),
             local_device_info->sync_user_agent());
 
diff --git a/components/sync_device_info/local_device_info_util_unittest.cc b/components/sync_device_info/local_device_info_util_unittest.cc
index ef9bcef..7a06eb7a 100644
--- a/components/sync_device_info/local_device_info_util_unittest.cc
+++ b/components/sync_device_info/local_device_info_util_unittest.cc
@@ -20,29 +20,29 @@
 
 // Call GetPersonalizableDeviceNameBlocking and make sure its return
 // value looks sane.
-TEST(GetSessionNameTest, GetPersonalizableDeviceNameBlocking) {
-  const std::string& session_name = GetPersonalizableDeviceNameBlocking();
-  EXPECT_FALSE(session_name.empty());
+TEST(GetClientNameTest, GetPersonalizableDeviceNameBlocking) {
+  const std::string& client_name = GetPersonalizableDeviceNameBlocking();
+  EXPECT_FALSE(client_name.empty());
 }
 
 #if defined(OS_CHROMEOS)
 
 // Call GetPersonalizableDeviceNameBlocking on ChromeOS where the
 // board type is CHROMEBOOK and make sure the return value is "Chromebook".
-TEST(GetSessionNameTest, GetPersonalizableDeviceNameBlockingChromebook) {
+TEST(GetClientNameTest, GetPersonalizableDeviceNameBlockingChromebook) {
   const char* kLsbRelease = "DEVICETYPE=CHROMEBOOK\n";
   base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
-  const std::string& session_name = GetPersonalizableDeviceNameBlocking();
-  EXPECT_EQ("Chromebook", session_name);
+  const std::string& client_name = GetPersonalizableDeviceNameBlocking();
+  EXPECT_EQ("Chromebook", client_name);
 }
 
 // Call GetPersonalizableDeviceNameBlocking on ChromeOS where the
 // board type is a CHROMEBOX and make sure the return value is "Chromebox".
-TEST(GetSessionNameTest, GetPersonalizableDeviceNameBlockingChromebox) {
+TEST(GetClientNameTest, GetPersonalizableDeviceNameBlockingChromebox) {
   const char* kLsbRelease = "DEVICETYPE=CHROMEBOX\n";
   base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
-  const std::string& session_name = GetPersonalizableDeviceNameBlocking();
-  EXPECT_EQ("Chromebox", session_name);
+  const std::string& client_name = GetPersonalizableDeviceNameBlocking();
+  EXPECT_EQ("Chromebox", client_name);
 }
 
 #endif  // OS_CHROMEOS
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 891679f..02612b5 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -111,7 +111,6 @@
   "+third_party/blink/public/platform/web_screen_info.h",
   "+third_party/blink/public/platform/web_scroll_into_view_params.h",
   "+third_party/blink/public/platform/web_scroll_types.h",
-  "+third_party/blink/public/platform/web_security_style.h",
   "+third_party/blink/public/platform/web_sudden_termination_disabler_type.h",
   "+third_party/blink/public/platform/web_text_autosizer_page_info.h",
   "+third_party/blink/public/platform/web_touch_event.h",
diff --git a/content/browser/devtools/protocol/devtools_protocol_test_support.cc b/content/browser/devtools/protocol/devtools_protocol_test_support.cc
index be018f6..423a324 100644
--- a/content/browser/devtools/protocol/devtools_protocol_test_support.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_test_support.cc
@@ -139,7 +139,7 @@
   return std::move(waiting_for_notification_params_);
 }
 
-blink::WebSecurityStyle DevToolsProtocolTest::GetSecurityStyle(
+blink::SecurityStyle DevToolsProtocolTest::GetSecurityStyle(
     content::WebContents* web_contents,
     content::SecurityStyleExplanations* security_style_explanations) {
   security_style_explanations->secure_explanations.push_back(
@@ -147,7 +147,7 @@
           "an explanation title", "an explanation summary",
           "an explanation description", cert_,
           blink::WebMixedContentContextType::kNotMixedContent));
-  return blink::kWebSecurityStyleNeutral;
+  return blink::SecurityStyle::kNeutral;
 }
 
 std::unique_ptr<base::DictionaryValue>
diff --git a/content/browser/devtools/protocol/devtools_protocol_test_support.h b/content/browser/devtools/protocol/devtools_protocol_test_support.h
index 23d51162..784d674cd 100644
--- a/content/browser/devtools/protocol/devtools_protocol_test_support.h
+++ b/content/browser/devtools/protocol/devtools_protocol_test_support.h
@@ -36,7 +36,7 @@
                               int32_t line_no,
                               const base::string16& source_id) override;
 
-  blink::WebSecurityStyle GetSecurityStyle(
+  blink::SecurityStyle GetSecurityStyle(
       content::WebContents* web_contents,
       content::SecurityStyleExplanations* security_style_explanations) override;
 
diff --git a/content/browser/devtools/protocol/security_handler.cc b/content/browser/devtools/protocol/security_handler.cc
index 7ed5ff93..de2460a 100644
--- a/content/browser/devtools/protocol/security_handler.cc
+++ b/content/browser/devtools/protocol/security_handler.cc
@@ -32,15 +32,15 @@
 namespace {
 
 std::string SecurityStyleToProtocolSecurityState(
-    blink::WebSecurityStyle security_style) {
+    blink::SecurityStyle security_style) {
   switch (security_style) {
-    case blink::kWebSecurityStyleUnknown:
+    case blink::SecurityStyle::kUnknown:
       return Security::SecurityStateEnum::Unknown;
-    case blink::kWebSecurityStyleNeutral:
+    case blink::SecurityStyle::kNeutral:
       return Security::SecurityStateEnum::Neutral;
-    case blink::kWebSecurityStyleInsecure:
+    case blink::SecurityStyle::kInsecure:
       return Security::SecurityStateEnum::Insecure;
-    case blink::kWebSecurityStyleSecure:
+    case blink::SecurityStyle::kSecure:
       return Security::SecurityStateEnum::Secure;
     default:
       NOTREACHED();
@@ -149,7 +149,7 @@
     return;
 
   SecurityStyleExplanations security_style_explanations;
-  blink::WebSecurityStyle security_style =
+  blink::SecurityStyle security_style =
       web_contents()->GetDelegate()->GetSecurityStyle(
           web_contents(), &security_style_explanations);
 
diff --git a/content/browser/frame_host/back_forward_cache_metrics.cc b/content/browser/frame_host/back_forward_cache_metrics.cc
index 4a22d44b..1d8bdf64 100644
--- a/content/browser/frame_host/back_forward_cache_metrics.cc
+++ b/content/browser/frame_host/back_forward_cache_metrics.cc
@@ -193,7 +193,7 @@
   // TODO(hajimehoshi): Use kNotCachedDueToExperimentCondition if the
   // experiment condition does not match.
   HistoryNavigationOutcome outcome = HistoryNavigationOutcome::kNotCached;
-  if (navigation->is_served_from_back_forward_cache()) {
+  if (navigation->IsServedFromBackForwardCache()) {
     outcome = HistoryNavigationOutcome::kRestored;
 
     UMA_HISTOGRAM_ENUMERATION(
@@ -207,7 +207,7 @@
   // have a value.
   if (evicted_reason_.has_value() ||
       last_committed_main_frame_navigation_id_ == -1) {
-    DCHECK(!navigation->is_served_from_back_forward_cache());
+    DCHECK(!navigation->IsServedFromBackForwardCache());
     outcome = HistoryNavigationOutcome::kEvicted;
   }
   UMA_HISTOGRAM_ENUMERATION("BackForwardCache.HistoryNavigationOutcome",
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 7e0df0a..556c04f 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -1155,7 +1155,7 @@
   if (!NeedsUrlLoader()) {
     // The types of pages that don't need a URL Loader should never get served
     // from the BackForwardCache.
-    DCHECK(!is_served_from_back_forward_cache());
+    DCHECK(!IsServedFromBackForwardCache());
 
     // There is no need to make a network request for this navigation, so commit
     // it immediately.
@@ -1641,7 +1641,7 @@
   }
 
   // Select an appropriate renderer to commit the navigation.
-  if (is_served_from_back_forward_cache()) {
+  if (IsServedFromBackForwardCache()) {
     NavigationControllerImpl* controller =
         static_cast<NavigationControllerImpl*>(
             frame_tree_node_->navigator()->GetController());
@@ -2141,7 +2141,7 @@
           OriginPolicyThrottle::ShouldRequestOriginPolicy(common_params_->url)),
       std::move(navigation_ui_data), service_worker_handle_.get(),
       appcache_handle_.get(), std::move(prefetched_signed_exchange_cache_),
-      this, is_served_from_back_forward_cache(), std::move(interceptor));
+      this, IsServedFromBackForwardCache(), std::move(interceptor));
 
   DCHECK(!render_frame_host_);
 }
@@ -2367,7 +2367,7 @@
   DCHECK(!common_params_->url.SchemeIs(url::kJavaScriptScheme));
   DCHECK(!IsRendererDebugURL(common_params_->url));
 
-  if (is_served_from_back_forward_cache()) {
+  if (IsServedFromBackForwardCache()) {
     NavigationControllerImpl* controller =
         static_cast<NavigationControllerImpl*>(
             frame_tree_node_->navigator()->GetController());
@@ -3771,6 +3771,10 @@
   return previous_render_frame_host_id_;
 }
 
+bool NavigationRequest::IsServedFromBackForwardCache() {
+  return rfh_restored_from_back_forward_cache_ != nullptr;
+}
+
 // static
 NavigationRequest* NavigationRequest::From(NavigationHandle* handle) {
   return static_cast<NavigationRequest*>(handle);
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index affb435..9483ea6 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -251,6 +251,7 @@
   void RegisterSubresourceOverride(
       mojom::TransferrableURLLoaderPtr transferrable_loader) override;
   GlobalFrameRoutingId GetPreviousRenderFrameHostId() override;
+  bool IsServedFromBackForwardCache() override;
 
   // Called on the UI thread by the Navigator to start the navigation.
   // The NavigationRequest can be deleted while BeginNavigation() is called.
@@ -465,11 +466,6 @@
     response_headers_for_testing_ = response_headers;
   }
 
-  // Whether this navigation was served from the back-forward cache.
-  bool is_served_from_back_forward_cache() {
-    return rfh_restored_from_back_forward_cache_ != nullptr;
-  }
-
   RenderFrameHostImpl* rfh_restored_from_back_forward_cache() {
     return rfh_restored_from_back_forward_cache_;
   }
diff --git a/content/browser/frame_host/navigator.h b/content/browser/frame_host/navigator.h
index 007c04c3..8ffb3f6 100644
--- a/content/browser/frame_host/navigator.h
+++ b/content/browser/frame_host/navigator.h
@@ -191,14 +191,6 @@
       const base::TimeTicks& renderer_before_unload_start_time,
       const base::TimeTicks& renderer_before_unload_end_time) {}
 
-  // Called when a navigation has failed or the response is 204/205 to discard
-  // the pending entry in order to avoid url spoofs. |expected_pending_entry_id|
-  // is the ID of the pending NavigationEntry at the start of the navigation.
-  // With sufficiently bad interleaving of IPCs, this may no longer be the
-  // pending NavigationEntry, in which case the pending NavigationEntry will not
-  // be discarded.
-  virtual void DiscardPendingEntryIfNeeded(int expected_pending_entry_id) {}
-
  protected:
   friend class base::RefCounted<Navigator>;
   virtual ~Navigator() {}
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index f8b0b93..3c50f33 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -322,6 +322,39 @@
   bool disabled_;
 };
 
+class ActiveURLMessageFilter : public mojo::MessageFilter {
+ public:
+  explicit ActiveURLMessageFilter(RenderFrameHostImpl* render_frame_host)
+      : render_frame_host_(render_frame_host) {}
+
+  ~ActiveURLMessageFilter() override {
+    if (debug_url_set_) {
+      GetContentClient()->SetActiveURL(GURL(), "");
+    }
+  }
+
+  // mojo::MessageFilter overrides.
+  bool WillDispatch(mojo::Message* message) override {
+    debug_url_set_ = true;
+    auto* frame_tree_node = render_frame_host_->frame_tree_node();
+    GetContentClient()->SetActiveURL(frame_tree_node->current_url(),
+                                     frame_tree_node->frame_tree()
+                                         ->root()
+                                         ->current_origin()
+                                         .GetDebugString());
+    return true;
+  }
+
+  void DidDispatchOrReject(mojo::Message* message, bool accepted) override {
+    GetContentClient()->SetActiveURL(GURL(), "");
+    debug_url_set_ = false;
+  }
+
+ private:
+  RenderFrameHostImpl* render_frame_host_;
+  bool debug_url_set_ = false;
+};
+
 void GrantFileAccess(int child_id,
                      const std::vector<base::FilePath>& file_paths) {
   ChildProcessSecurityPolicyImpl* policy =
@@ -1512,8 +1545,6 @@
 
   // Crash reports triggered by IPC messages for this frame should be associated
   // with its URL.
-  // TODO(lukasza): Also call SetActiveURL for mojo messages dispatched to
-  // either the FrameHost interface or to interfaces bound by this frame.
   ScopedActiveURL scoped_active_url(this);
 
   if (delegate_->OnMessageReceived(this, msg))
@@ -4110,6 +4141,8 @@
       FilterRendererExposedInterfaces(mojom::kNavigation_FrameSpec,
                                       GetProcess()->GetID(),
                                       std::move(interface_provider_request)));
+  document_scoped_interface_provider_binding_.SetFilter(
+      std::make_unique<ActiveURLMessageFilter>(this));
 }
 
 void RenderFrameHostImpl::BindDocumentInterfaceBrokerReceiver(
@@ -4120,15 +4153,20 @@
   DCHECK(!document_interface_broker_content_receiver_.is_bound());
   DCHECK(content_receiver.is_valid());
   document_interface_broker_content_receiver_.Bind(std::move(content_receiver));
+  document_interface_broker_content_receiver_.SetFilter(
+      std::make_unique<ActiveURLMessageFilter>(this));
   DCHECK(!document_interface_broker_blink_receiver_.is_bound());
   DCHECK(blink_receiver.is_valid());
   document_interface_broker_blink_receiver_.Bind(std::move(blink_receiver));
+  document_interface_broker_blink_receiver_.SetFilter(
+      std::make_unique<ActiveURLMessageFilter>(this));
 }
 
 void RenderFrameHostImpl::BindBrowserInterfaceBrokerReceiver(
     mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker> receiver) {
   DCHECK(receiver.is_valid());
   broker_receiver_.Bind(std::move(receiver));
+  broker_receiver_.SetFilter(std::make_unique<ActiveURLMessageFilter>(this));
 }
 
 void RenderFrameHostImpl::SetKeepAliveTimeoutForTesting(
@@ -5650,6 +5688,8 @@
       [](RenderFrameHostImpl* impl,
          mojo::PendingAssociatedReceiver<mojom::FrameHost> receiver) {
         impl->frame_host_associated_receiver_.Bind(std::move(receiver));
+        impl->frame_host_associated_receiver_.SetFilter(
+            std::make_unique<ActiveURLMessageFilter>(impl));
       };
   associated_registry_->AddInterface(
       base::BindRepeating(bind_frame_host_receiver, base::Unretained(this)));
@@ -6063,15 +6103,6 @@
     GrantFileAccessFromResourceRequestBody(*common_params.post_data);
 }
 
-std::set<int> RenderFrameHostImpl::GetNavigationEntryIdsPendingCommit() {
-  std::set<int> result;
-  if (navigation_request_)
-    result.insert(navigation_request_->nav_entry_id());
-  for (auto const& requests : navigation_requests_)
-    result.insert(requests.second->nav_entry_id());
-  return result;
-}
-
 mojo::AssociatedRemote<mojom::NavigationClient>
 RenderFrameHostImpl::GetNavigationClientFromInterfaceProvider() {
   mojo::AssociatedRemote<mojom::NavigationClient> navigation_client_remote;
@@ -7866,4 +7897,8 @@
   return navigation_entry->back_forward_cache_metrics();
 }
 
+bool RenderFrameHostImpl::HasPendingCommitNavigationForTesting() {
+  return navigation_request_ || !navigation_requests_.empty();
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index bd2c63f..3a6a608 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -931,10 +931,6 @@
   // for unload handler processing.
   void SetSubframeUnloadTimeoutForTesting(const base::TimeDelta& timeout);
 
-  // Returns the list of NavigationEntry ids corresponding to NavigationRequests
-  // waiting to commit in this RenderFrameHost.
-  std::set<int> GetNavigationEntryIdsPendingCommit();
-
   service_manager::BinderRegistry& BinderRegistryForTesting() {
     return *registry_;
   }
@@ -1190,6 +1186,10 @@
 
   const std::string& GetEncoding() const { return canonical_encoding_; }
 
+  // Return true if this contains at least one NavigationRequest waiting to
+  // commit in this RenderFrameHost.
+  bool HasPendingCommitNavigationForTesting();
+
   base::WeakPtr<RenderFrameHostImpl> GetWeakPtr();
 
  protected:
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
index 913c7bc..c21e071d 100644
--- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -1964,7 +1964,7 @@
 }
 
 // This test makes sure that when a blocked frame commits with a different URL,
-// it doesn't lead to a leaked NavigationHandle.  This is a regression test for
+// it doesn't lead to a leaked NavigationHandle. This is a regression test for
 // https://crbug.com/872803.
 IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
                        ErrorPagesShouldntLeakNavigationHandles) {
@@ -1975,32 +1975,31 @@
   GURL blocked_url(embedded_test_server()->GetURL(
       "blocked.com", "/frame-ancestors-none.html"));
   WebContents* web_contents = shell()->web_contents();
-  NavigationHandleObserver nav_handle_observer(web_contents, blocked_url);
+  NavigationHandleObserver navigation_observer(web_contents, blocked_url);
   EXPECT_TRUE(NavigateIframeToURL(web_contents, "child0", blocked_url));
 
   // Verify that the NavigationHandle / NavigationRequest didn't leak.
   RenderFrameHostImpl* frame = static_cast<RenderFrameHostImpl*>(
       shell()->web_contents()->GetAllFrames()[1]);
-  EXPECT_EQ(0u, frame->GetNavigationEntryIdsPendingCommit().size());
+  EXPECT_FALSE(frame->HasPendingCommitNavigationForTesting());
 
   // TODO(lukasza, clamy): https://crbug.com/784904: Verify that
   // WebContentsObserver::DidFinishNavigation was called with the same
-  // NavigationHandle as WebContentsObserver::DidStartNavigation.  This requires
+  // NavigationHandle as WebContentsObserver::DidStartNavigation. This requires
   // properly matching the commit IPC to the NavigationHandle (ignoring that
   // their URLs do not match - matching instead using navigation id or mojo
   // interface identity).
-  //
-  // Subsequent checks don't make sense before WCO::DidFinishNavigation is
-  // called - this is why ASSERT_TRUE is used here.
-  //   ASSERT_TRUE(nav_handle_observer.has_committed());
-  //   EXPECT_EQ(net::ERR_BLOCKED_BY_RESPONSE,
-  //       nav_handle_observer.net_error_code());
 
-  // TODO(lukasza): https://crbug.com/759184: Verify
-  // |nav_handle_observer.last_committed_url()| below - this should be possible
-  // once we handle frame-ancestors CSP in the browser process and commit it
-  // with the original URL.
-  //   EXPECT_EQ(blocked_url, nav_handle_observer.last_committed_url());
+  // TODO(https://crbug.com/759184): Verify CSP frame-ancestors in the browser
+  // process. Currently, this is done by the renderer process, which commits an
+  // empty document with success instead.
+  //  EXPECT_EQ(blocked_url, navigation_observer.last_committed_url());
+  //  EXPECT_EQ(net::ERR_BLOCKED_BY_RESPONSE,
+  //            navigation_obsever.net_error_code());
+  EXPECT_TRUE(navigation_observer.has_committed());
+  EXPECT_FALSE(navigation_observer.is_error());
+  EXPECT_EQ(GURL("data:,"), navigation_observer.last_committed_url());
+  EXPECT_EQ(net::Error::OK, navigation_observer.net_error_code());
 }
 
 IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 7ffd769..11292ee7 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -655,7 +655,7 @@
 
 void RenderFrameHostManager::DidCreateNavigationRequest(
     NavigationRequest* request) {
-  if (request->is_served_from_back_forward_cache()) {
+  if (request->IsServedFromBackForwardCache()) {
     // Since the frame from the back-forward cache is being committed to the
     // SiteInstance we already have, it is treated as current.
     request->set_associated_site_instance_type(
@@ -704,26 +704,8 @@
     // not be recreated if the URL didn't change. So instead of calling
     // CleanUpNavigation just discard the speculative RenderFrameHost if one
     // exists.
-    if (speculative_render_frame_host_) {
-      // If the speculative RenderFrameHost is trying to commit a navigation,
-      // inform the NavigationController that the load of the corresponding
-      // NavigationEntry stopped if needed. This is the case if the new
-      // navigation was started from BeginNavigation. If the navigation was
-      // started through the NavigationController, the NavigationController has
-      // already updated its state properly, and doesn't need to be notified.
-      // Note: We query all NavigationEntry IDs fom the RenderFrameHost, however
-      // at most one call to DiscardPendingEntryIfNeeded will succeed. Since we
-      // don't know which of the entries is the pending one, we have to try them
-      // all.
-      // TODO(clamy): Clean this up.
-      if (request->from_begin_navigation()) {
-        std::set<int> ids = speculative_render_frame_host_
-                                ->GetNavigationEntryIdsPendingCommit();
-        for (int id : ids)
-          frame_tree_node_->navigator()->DiscardPendingEntryIfNeeded(id);
-      }
+    if (speculative_render_frame_host_)
       DiscardUnusedFrame(UnsetSpeculativeRenderFrameHost());
-    }
 
     // Short-term solution: avoid creating a WebUI for subframes because
     // non-PlzNavigate code path doesn't do it and some WebUI pages don't
@@ -748,25 +730,6 @@
     if (!speculative_render_frame_host_ ||
         speculative_render_frame_host_->GetSiteInstance() !=
             dest_site_instance.get()) {
-      // If there is a speculative RenderFrameHost trying to commit a
-      // navigation, inform the NavigationController that the load of the
-      // corresponding NavigationEntry stopped if needed. This is the case if
-      // the new navigation was started from BeginNavigation. If the navigation
-      // was started through the NavigationController, the NavigationController
-      // has already updated its state properly, and doesn't need to be
-      // notified.
-      // Note: We query all NavigationEntry IDs fom the RenderFrameHost, however
-      // at most one call to DiscardPendingEntryIfNeeded will succeed. Since we
-      // don't know which of the entries is the pending one, we have to try them
-      // all.
-      // TODO(clamy): Clean this up.
-      if (request->from_begin_navigation() && speculative_render_frame_host_) {
-        std::set<int> ids = speculative_render_frame_host_
-                                ->GetNavigationEntryIdsPendingCommit();
-        for (int id : ids)
-          frame_tree_node_->navigator()->DiscardPendingEntryIfNeeded(id);
-      }
-
       // If a previous speculative RenderFrameHost didn't exist or if its
       // SiteInstance differs from the one for the current URL, a new one needs
       // to be created.
diff --git a/content/browser/media/mpris_notifier.cc b/content/browser/media/mpris_notifier.cc
index 0839cdd..3b34a30 100644
--- a/content/browser/media/mpris_notifier.cc
+++ b/content/browser/media/mpris_notifier.cc
@@ -35,11 +35,11 @@
   connector_->BindInterface(media_session::mojom::kServiceName,
                             mojo::MakeRequest(&controller_manager_ptr));
   controller_manager_ptr->CreateActiveMediaController(
-      mojo::MakeRequest(&media_controller_ptr_));
+      media_controller_.BindNewPipeAndPassReceiver());
 
   // Observe the active media controller for changes to playback state and
   // supported actions.
-  media_controller_ptr_->AddObserver(
+  media_controller_->AddObserver(
       media_controller_observer_receiver_.BindNewPipeAndPassRemote());
 }
 
diff --git a/content/browser/media/mpris_notifier.h b/content/browser/media/mpris_notifier.h
index 8813ed1..9610800 100644
--- a/content/browser/media/mpris_notifier.h
+++ b/content/browser/media/mpris_notifier.h
@@ -10,6 +10,7 @@
 
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/media_session/public/mojom/media_controller.mojom.h"
 
 namespace mpris {
@@ -61,7 +62,7 @@
   service_manager::Connector* connector_;
 
   // Tracks current media session state/metadata.
-  media_session::mojom::MediaControllerPtr media_controller_ptr_;
+  mojo::Remote<media_session::mojom::MediaController> media_controller_;
   media_session::mojom::MediaSessionInfoPtr session_info_;
 
   // Used to receive updates to the active media controller.
diff --git a/content/browser/media/now_playing_info_center_notifier.cc b/content/browser/media/now_playing_info_center_notifier.cc
index e586a4d8..25fc859 100644
--- a/content/browser/media/now_playing_info_center_notifier.cc
+++ b/content/browser/media/now_playing_info_center_notifier.cc
@@ -30,11 +30,11 @@
   connector->BindInterface(media_session::mojom::kServiceName,
                            mojo::MakeRequest(&controller_manager_ptr));
   controller_manager_ptr->CreateActiveMediaController(
-      mojo::MakeRequest(&media_controller_ptr_));
+      media_controller_.BindNewPipeAndPassReceiver());
 
   // Observe the active media controller for changes to playback state and
   // supported actions.
-  media_controller_ptr_->AddObserver(
+  media_controller_->AddObserver(
       media_controller_observer_receiver_.BindNewPipeAndPassRemote());
 }
 
diff --git a/content/browser/media/now_playing_info_center_notifier.h b/content/browser/media/now_playing_info_center_notifier.h
index 9eb9d7e..9189e870 100644
--- a/content/browser/media/now_playing_info_center_notifier.h
+++ b/content/browser/media/now_playing_info_center_notifier.h
@@ -10,6 +10,7 @@
 
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/media_session/public/mojom/media_controller.mojom.h"
 
 namespace now_playing {
@@ -54,7 +55,7 @@
       now_playing_info_center_delegate_;
 
   // Tracks current media session state/metadata.
-  media_session::mojom::MediaControllerPtr media_controller_ptr_;
+  mojo::Remote<media_session::mojom::MediaController> media_controller_;
   media_session::mojom::MediaSessionInfoPtr session_info_;
 
   // Used to receive updates to the active media controller.
diff --git a/content/browser/media/system_media_controls_notifier.cc b/content/browser/media/system_media_controls_notifier.cc
index 2fabf79..e1179ad 100644
--- a/content/browser/media/system_media_controls_notifier.cc
+++ b/content/browser/media/system_media_controls_notifier.cc
@@ -62,15 +62,15 @@
   connector_->BindInterface(media_session::mojom::kServiceName,
                             mojo::MakeRequest(&controller_manager_ptr));
   controller_manager_ptr->CreateActiveMediaController(
-      mojo::MakeRequest(&media_controller_ptr_));
+      media_controller_.BindNewPipeAndPassReceiver());
 
   // Observe the active media controller for changes to playback state and
   // supported actions.
-  media_controller_ptr_->AddObserver(
+  media_controller_->AddObserver(
       media_controller_observer_receiver_.BindNewPipeAndPassRemote());
 
   // Observe the active media controller for changes to provided artwork.
-  media_controller_ptr_->ObserveImages(
+  media_controller_->ObserveImages(
       media_session::mojom::MediaSessionImageType::kArtwork, kMinImageSize,
       kDesiredImageSize,
       media_controller_image_observer_receiver_.BindNewPipeAndPassRemote());
diff --git a/content/browser/media/system_media_controls_notifier.h b/content/browser/media/system_media_controls_notifier.h
index c403ea9..020ed07 100644
--- a/content/browser/media/system_media_controls_notifier.h
+++ b/content/browser/media/system_media_controls_notifier.h
@@ -11,8 +11,8 @@
 #include "base/sequence_checker.h"
 #include "base/timer/timer.h"
 #include "content/common/content_export.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/media_session/public/mojom/media_controller.mojom.h"
 
 namespace system_media_controls {
@@ -90,7 +90,7 @@
   service_manager::Connector* connector_;
 
   // Tracks current media session state/metadata.
-  media_session::mojom::MediaControllerPtr media_controller_ptr_;
+  mojo::Remote<media_session::mojom::MediaController> media_controller_;
   media_session::mojom::MediaSessionInfoPtr session_info_ptr_;
 
   // Used to receive updates to the active media controller.
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index 81b0494..f87a421 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -45,6 +45,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/navigation_handle_observer.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
@@ -759,13 +760,19 @@
       shell()->web_contents()->GetMainFrame());
   RenderProcessHostKillWaiter kill_waiter(frame->GetProcess());
 
+  NavigationHandleObserver navigation_observer(shell()->web_contents(),
+                                               non_same_document_url);
   ScopedInterfaceParamsReplacer replacer(shell()->web_contents(), nullptr);
   EXPECT_TRUE(NavigateToURLAndExpectNoCommit(shell(), non_same_document_url));
   EXPECT_EQ(bad_message::RFH_INTERFACE_PROVIDER_MISSING, kill_waiter.Wait());
 
-  // Verify that the death of the renderer process doesn't leave behing and leak
-  // NavigationRequests - see https://crbug.com/869193.
-  EXPECT_EQ(0u, frame->GetNavigationEntryIdsPendingCommit().size());
+  // Verify that the death of the renderer process doesn't leave behind and
+  // leak NavigationRequests - see https://crbug.com/869193.
+  EXPECT_FALSE(frame->HasPendingCommitNavigationForTesting());
+  EXPECT_FALSE(navigation_observer.has_committed());
+  EXPECT_TRUE(navigation_observer.is_error());
+  EXPECT_TRUE(navigation_observer.last_committed_url().is_empty());
+  EXPECT_EQ(net::OK, navigation_observer.net_error_code());
 }
 
 // Test that a compromised renderer cannot ask to upload an arbitrary file in
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 3e6ff3e45..b04e400 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -153,9 +153,9 @@
 #include "third_party/blink/public/common/frame/sandbox_flags.h"
 #include "third_party/blink/public/common/mime_util/mime_util.h"
 #include "third_party/blink/public/common/page/page_zoom.h"
+#include "third_party/blink/public/common/security/security_style.h"
 #include "third_party/blink/public/mojom/loader/pause_subresource_loading_handle.mojom.h"
 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
-#include "third_party/blink/public/platform/web_security_style.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/accessibility/ax_tree_combiner.h"
 #include "ui/base/layout.h"
diff --git a/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc b/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
index cc15b70..55e272e6 100644
--- a/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
+++ b/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
@@ -286,6 +286,17 @@
       // Shutdown the server.
       EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
 
+      // The HTTP Cache does not currently support cross-origin prefetching if
+      // the split cache is enabled, so skip the rest of the tests.
+      // TODO(crbug.com/939317): Remove this early return when cross-origin
+      // prefetching with split cache works.
+      if (base::FeatureList::IsEnabled(
+              net::features::kSplitCacheByNetworkIsolationKey) &&
+          !url::Origin::Create(sxg_url).IsSameOriginWith(
+              url::Origin::Create(inner_url))) {
+        return;
+      }
+
       // Need to setup MockSignedExchangeHandlerFactory because the SXG is
       // loaded from HTTPCache.
       MockSignedExchangeHandlerFactory factory({MockSignedExchangeHandlerParams(
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 82d6006..49cb37e 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -48,6 +48,9 @@
     const base::CommandLine& command_line) {
   // Please consider setting up feature defaults for different platforms
   // in runtime_enabled_features.json5 instead of here
+  // TODO(rodneyding): Move the more common cases here
+  // to baseFeature/switch functions below and move more complex
+  // ones to special case functions.
 #if defined(USE_AURA)
   WebRuntimeFeatures::EnableCompositedSelectionUpdate(true);
 #endif
@@ -258,9 +261,6 @@
       base::FeatureList::IsEnabled(
           features::kAllowContentInitiatedDataUrlNavigations));
 
-  WebRuntimeFeatures::EnableResourceLoadScheduler(
-      base::FeatureList::IsEnabled(features::kResourceLoadScheduler));
-
   if (base::FeatureList::IsEnabled(features::kBuiltInModuleAll))
     WebRuntimeFeatures::EnableBuiltInModuleAll(true);
 
@@ -441,83 +441,75 @@
       base::FeatureList::IsEnabled(features::kDocumentPolicy));
 }
 
+// Helper class that describes the desired enable/disable action
+// for a runtime feature when a command line switch exists.
+struct SwitchToFeatureMap {
+  // The enabler function defined in web_runtime_features.cc.
+  void (*feature_enabler)(bool);
+  // The switch to check for on command line.
+  const char* switch_name;
+  // This is the desired state for the runtime feature if the
+  // switch exists on command line.
+  bool target_enabled_state;
+};
+
 // Sets blink runtime features controlled by command line switches.
 void SetRuntimeFeaturesFromCommandLine(const base::CommandLine& command_line) {
-  if (command_line.HasSwitch(switches::kDisableDatabases))
-    WebRuntimeFeatures::EnableDatabase(false);
-
-  if (command_line.HasSwitch(switches::kDisableNotifications)) {
-    WebRuntimeFeatures::EnableNotifications(false);
-
-    // Chrome's Push Messaging implementation relies on Web Notifications.
-    WebRuntimeFeatures::EnablePushMessaging(false);
+  // To add a new switch-controlled runtime feature, add a new
+  // SwitchToFeatureMap entry to the initializer list below.
+  // Note: command line switches are now discouraged, please consider
+  // using base::Feature instead.
+  // https://chromium.googlesource.com/chromium/src/+/refs/heads/master/docs/configuration.md#switches
+  using wrf = WebRuntimeFeatures;
+  const SwitchToFeatureMap switchToFeatureMapping[] = {
+      // Stable Features
+      {wrf::EnablePermissionsAPI, switches::kDisablePermissionsAPI, false},
+      {wrf::EnablePresentationAPI, switches::kDisablePresentationAPI, false},
+      {wrf::EnableRemotePlaybackAPI, switches::kDisableRemotePlaybackAPI,
+       false},
+      {wrf::EnableTimerThrottlingForBackgroundTabs,
+       switches::kDisableBackgroundTimerThrottling, false},
+      // End of Stable Features
+      {wrf::EnableDatabase, switches::kDisableDatabases, false},
+      {wrf::EnableNotifications, switches::kDisableNotifications, false},
+      // Chrome's Push Messaging implementation relies on Web Notifications.
+      {wrf::EnablePushMessaging, switches::kDisableNotifications, false},
+      {wrf::EnableSharedWorker, switches::kDisableSharedWorkers, false},
+      {wrf::EnableScriptedSpeechRecognition, switches::kDisableSpeechAPI,
+       false},
+      {wrf::EnableScriptedSpeechSynthesis, switches::kDisableSpeechAPI, false},
+      {wrf::EnableScriptedSpeechSynthesis, switches::kDisableSpeechSynthesisAPI,
+       false},
+      {wrf::EnableFileSystem, switches::kDisableFileSystem, false},
+      {wrf::EnableWebGLDraftExtensions, switches::kEnableWebGLDraftExtensions,
+       true},
+      {wrf::EnableAutomationControlled, switches::kEnableAutomation, true},
+      {wrf::EnableAutomationControlled, switches::kHeadless, true},
+      {wrf::EnableAutomationControlled, switches::kRemoteDebuggingPipe, true},
+      {wrf::EnableAutomationControlled, switches::kRemoteDebuggingPort, true},
+      {wrf::ForceOverlayFullscreenVideo, switches::kForceOverlayFullscreenVideo,
+       true},
+      {wrf::EnablePreciseMemoryInfo, switches::kEnablePreciseMemoryInfo, true},
+      {wrf::EnablePrintBrowser, switches::kEnablePrintBrowser, true},
+      {wrf::EnableNetInfoDownlinkMax,
+       switches::kEnableNetworkInformationDownlinkMax, true},
+      {wrf::EnablePermissionsAPI, switches::kDisablePermissionsAPI, false},
+      {wrf::EnableWebGPU, switches::kEnableUnsafeWebGPU, true},
+      {wrf::EnableWebVR, switches::kEnableWebVR, true},
+      {wrf::EnablePresentationAPI, switches::kDisablePresentationAPI, false},
+      {wrf::EnableRemotePlaybackAPI, switches::kDisableRemotePlaybackAPI,
+       false},
+      {wrf::EnableTimerThrottlingForBackgroundTabs,
+       switches::kDisableBackgroundTimerThrottling, false},
+      {wrf::EnableAccessibilityObjectModel,
+       switches::kEnableAccessibilityObjectModel, true},
+      {wrf::EnableAllowSyncXHRInPageDismissal,
+       switches::kAllowSyncXHRInPageDismissal, true},
+  };
+  for (const auto& mapping : switchToFeatureMapping) {
+    if (command_line.HasSwitch(mapping.switch_name))
+      mapping.feature_enabler(mapping.target_enabled_state);
   }
-
-  if (command_line.HasSwitch(switches::kDisableSharedWorkers))
-    WebRuntimeFeatures::EnableSharedWorker(false);
-
-  if (command_line.HasSwitch(switches::kDisableSpeechAPI)) {
-    WebRuntimeFeatures::EnableScriptedSpeechRecognition(false);
-    WebRuntimeFeatures::EnableScriptedSpeechSynthesis(false);
-  }
-
-  if (command_line.HasSwitch(switches::kDisableSpeechSynthesisAPI)) {
-    WebRuntimeFeatures::EnableScriptedSpeechSynthesis(false);
-  }
-
-  if (command_line.HasSwitch(switches::kDisableFileSystem))
-    WebRuntimeFeatures::EnableFileSystem(false);
-
-  if (command_line.HasSwitch(switches::kEnableWebGLDraftExtensions))
-    WebRuntimeFeatures::EnableWebGLDraftExtensions(true);
-
-  if (command_line.HasSwitch(switches::kEnableAutomation) ||
-      command_line.HasSwitch(switches::kHeadless) ||
-      command_line.HasSwitch(switches::kRemoteDebuggingPipe) ||
-      command_line.HasSwitch(switches::kRemoteDebuggingPort)) {
-    WebRuntimeFeatures::EnableAutomationControlled(true);
-  }
-
-  if (command_line.HasSwitch(switches::kForceOverlayFullscreenVideo))
-    WebRuntimeFeatures::ForceOverlayFullscreenVideo(true);
-
-  if (command_line.HasSwitch(switches::kEnablePreciseMemoryInfo))
-    WebRuntimeFeatures::EnablePreciseMemoryInfo(true);
-
-  if (command_line.HasSwitch(switches::kEnablePrintBrowser))
-    WebRuntimeFeatures::EnablePrintBrowser(true);
-
-  if (command_line.HasSwitch(switches::kEnableNetworkInformationDownlinkMax))
-    WebRuntimeFeatures::EnableNetInfoDownlinkMax(true);
-
-  if (command_line.HasSwitch(switches::kDisablePermissionsAPI))
-    WebRuntimeFeatures::EnablePermissionsAPI(false);
-
-  if (command_line.HasSwitch(switches::kDisableV8IdleTasks))
-    WebRuntimeFeatures::EnableV8IdleTasks(false);
-  else
-    WebRuntimeFeatures::EnableV8IdleTasks(true);
-
-  if (command_line.HasSwitch(switches::kEnableUnsafeWebGPU))
-    WebRuntimeFeatures::EnableWebGPU(true);
-
-  if (command_line.HasSwitch(switches::kEnableWebVR))
-    WebRuntimeFeatures::EnableWebVR(true);
-
-  if (command_line.HasSwitch(switches::kDisablePresentationAPI))
-    WebRuntimeFeatures::EnablePresentationAPI(false);
-
-  if (command_line.HasSwitch(switches::kDisableRemotePlaybackAPI))
-    WebRuntimeFeatures::EnableRemotePlaybackAPI(false);
-
-  if (command_line.HasSwitch(switches::kDisableBackgroundTimerThrottling))
-    WebRuntimeFeatures::EnableTimerThrottlingForBackgroundTabs(false);
-
-  if (command_line.HasSwitch(switches::kEnableAccessibilityObjectModel))
-    WebRuntimeFeatures::EnableAccessibilityObjectModel(true);
-
-  if (command_line.HasSwitch(switches::kAllowSyncXHRInPageDismissal))
-    WebRuntimeFeatures::EnableAllowSyncXHRInPageDismissal(true);
 }
 
 // Sets blink runtime features controlled by FieldTrial parameter values.
@@ -595,6 +587,11 @@
     WebRuntimeFeatures::EnableFeatureFromString("FileHandling", true);
   }
 
+  if (command_line.HasSwitch(switches::kDisableV8IdleTasks))
+    WebRuntimeFeatures::EnableV8IdleTasks(false);
+  else
+    WebRuntimeFeatures::EnableV8IdleTasks(true);
+
   // This is a hack to get the tests passing as they require
   // these blink features to be enabled while they are disabled
   // by base::Feature controls earlier in code.
@@ -630,6 +627,9 @@
     WebRuntimeFeatures::EnableOriginTrialControlledFeatures(false);
   }
 
+  // TODO(rodneyding): add doc explaining ways to add new runtime features
+  // controls in the following functions.
+
   SetRuntimeFeaturesFromChromiumFeatures();
 
   SetRuntimeFeaturesFromCommandLine(command_line);
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
index 263fb42..35a28b7 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
@@ -162,7 +162,12 @@
                 public void onConnectionLost(ChildProcessConnection connection) {
                     assert LauncherThread.runningOnLauncherThread();
                     if (connection.getPid() == 0) return;
-                    sLauncherByPid.remove(connection.getPid());
+
+                    ChildProcessLauncherHelperImpl result =
+                            sLauncherByPid.remove(connection.getPid());
+                    // Child process might die before onConnectionEstablished.
+                    if (result == null) return;
+
                     if (mBindingManager != null) mBindingManager.removeConnection(connection);
                     if (mRanking != null) {
                         setReverseRankWhenConnectionLost(mRanking.getReverseRank(connection));
diff --git a/content/public/browser/navigation_handle.h b/content/public/browser/navigation_handle.h
index 34e7d66a..d671551 100644
--- a/content/public/browser/navigation_handle.h
+++ b/content/public/browser/navigation_handle.h
@@ -163,6 +163,9 @@
   // handlers.
   virtual bool IsExternalProtocol() = 0;
 
+  // Whether the navigation is restoring a page from back-forward cache.
+  virtual bool IsServedFromBackForwardCache() = 0;
+
   // Navigation control flow --------------------------------------------------
 
   // The net error code if an error happened prior to commit. Otherwise it will
diff --git a/content/public/browser/security_style_explanations.h b/content/public/browser/security_style_explanations.h
index 5dd0047..a0df34f2 100644
--- a/content/public/browser/security_style_explanations.h
+++ b/content/public/browser/security_style_explanations.h
@@ -10,7 +10,7 @@
 
 #include "content/common/content_export.h"
 #include "content/public/browser/security_style_explanation.h"
-#include "third_party/blink/public/platform/web_security_style.h"
+#include "third_party/blink/public/common/security/security_style.h"
 
 namespace content {
 
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index 1f046dd..9dcdf2d 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -275,10 +275,10 @@
   return false;
 }
 
-blink::WebSecurityStyle WebContentsDelegate::GetSecurityStyle(
+blink::SecurityStyle WebContentsDelegate::GetSecurityStyle(
     WebContents* web_contents,
     SecurityStyleExplanations* security_style_explanations) {
-  return blink::kWebSecurityStyleUnknown;
+  return blink::SecurityStyle::kUnknown;
 }
 
 bool WebContentsDelegate::ShouldAllowRunningInsecureContent(
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index c761ce5..19a7b66 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -27,10 +27,10 @@
 #include "third_party/blink/public/common/frame/blocked_navigation_types.h"
 #include "third_party/blink/public/common/fullscreen/fullscreen_options.h"
 #include "third_party/blink/public/common/mediastream/media_stream_request.h"
+#include "third_party/blink/public/common/security/security_style.h"
 #include "third_party/blink/public/mojom/choosers/color_chooser.mojom-forward.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
 #include "third_party/blink/public/platform/web_drag_operation.h"
-#include "third_party/blink/public/platform/web_security_style.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -569,8 +569,8 @@
   // Can be overridden by a delegate to return the security style of the
   // given |web_contents|, populating |security_style_explanations| to
   // explain why the SecurityStyle was downgraded. Returns
-  // WebSecurityStyleUnknown if not overriden.
-  virtual blink::WebSecurityStyle GetSecurityStyle(
+  // SecurityStyleUnknown if not overriden.
+  virtual blink::SecurityStyle GetSecurityStyle(
       WebContents* web_contents,
       SecurityStyleExplanations* security_style_explanations);
 
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index b3c6a43..5411d32d 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -18,6 +18,7 @@
 #include "ipc/ipc_message_macros.h"
 #include "services/network/public/cpp/network_ipc_param_traits.h"
 #include "services/network/public/mojom/referrer_policy.mojom.h"
+#include "third_party/blink/public/common/security/security_style.h"
 #include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
 #include "third_party/blink/public/mojom/permissions/permission_status.mojom.h"
 #include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
@@ -26,7 +27,6 @@
 #include "third_party/blink/public/platform/web_history_scroll_restoration_type.h"
 #include "third_party/blink/public/platform/web_point.h"
 #include "third_party/blink/public/platform/web_rect.h"
-#include "third_party/blink/public/platform/web_security_style.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_event.h"
@@ -57,7 +57,7 @@
                           network::mojom::ReferrerPolicy::kMaxValue)
 IPC_ENUM_TRAITS_MAX_VALUE(blink::WebHistoryScrollRestorationType,
                           blink::kWebHistoryScrollRestorationManual)
-IPC_ENUM_TRAITS_MAX_VALUE(blink::WebSecurityStyle, blink::kWebSecurityStyleLast)
+IPC_ENUM_TRAITS_MAX_VALUE(blink::SecurityStyle, blink::SecurityStyle::kLast)
 IPC_ENUM_TRAITS_MAX_VALUE(blink::mojom::PermissionStatus,
                           blink::mojom::PermissionStatus::LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(cc::TouchAction, cc::kTouchActionMax)
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index ec56ae7..0f8bc4be 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -452,10 +452,6 @@
 const base::Feature kResamplingInputEvents{"ResamplingInputEvents",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Loading Dispatcher v0 support with ResourceLoadScheduler (crbug.com/729954).
-const base::Feature kResourceLoadScheduler{"ResourceLoadScheduler",
-                                           base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Run video capture service in the Browser process as opposed to a dedicated
 // utility process
 const base::Feature kRunVideoCaptureServiceInBrowserProcess{
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index da8a21e..fe32247 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -99,7 +99,6 @@
 CONTENT_EXPORT extern const base::Feature kRenderDocumentForSubframe;
 CONTENT_EXPORT extern const base::Feature kRequestUnbufferedDispatch;
 CONTENT_EXPORT extern const base::Feature kResamplingInputEvents;
-CONTENT_EXPORT extern const base::Feature kResourceLoadScheduler;
 CONTENT_EXPORT extern const base::Feature
     kRunVideoCaptureServiceInBrowserProcess;
 CONTENT_EXPORT extern const base::Feature kScrollAnchorSerialization;
diff --git a/content/public/test/mock_navigation_handle.h b/content/public/test/mock_navigation_handle.h
index a0259369..de5fac7c 100644
--- a/content/public/test/mock_navigation_handle.h
+++ b/content/public/test/mock_navigation_handle.h
@@ -37,6 +37,7 @@
   bool IsRendererInitiated() override { return true; }
   MOCK_METHOD0(GetFrameTreeNodeId, int());
   MOCK_METHOD0(GetPreviousRenderFrameHostId, GlobalFrameRoutingId());
+  bool IsServedFromBackForwardCache() override { return false; }
   RenderFrameHost* GetParentFrame() override {
     return render_frame_host_ ? render_frame_host_->GetParent() : nullptr;
   }
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index d11956c..267600e 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -220,8 +220,6 @@
     "navigation_state.h",
     "net_info_helper.cc",
     "net_info_helper.h",
-    "page_properties.cc",
-    "page_properties.h",
     "peripheral_content_heuristic.cc",
     "peripheral_content_heuristic.h",
     "queue_message_swap_promise.cc",
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index 1929454..96a5794 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -64,12 +64,12 @@
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/mime_util/mime_util.h"
+#include "third_party/blink/public/common/security/security_style.h"
 #include "third_party/blink/public/platform/file_path_conversion.h"
 #include "third_party/blink/public/platform/interface_provider.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_http_load_info.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
-#include "third_party/blink/public/platform/web_security_style.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/platform/web_url_error.h"
 #include "third_party/blink/public/platform/web_url_load_timing.h"
@@ -189,24 +189,24 @@
                                 WebURLResponse* response,
                                 bool report_security_info) {
   if (!report_security_info) {
-    response->SetSecurityStyle(blink::kWebSecurityStyleUnknown);
+    response->SetSecurityStyle(blink::SecurityStyle::kUnknown);
     return;
   }
   if (!url.SchemeIsCryptographic()) {
     // Some origins are considered secure even though they're not cryptographic,
     // so treat them as secure in the UI.
     if (IsOriginSecure(url))
-      response->SetSecurityStyle(blink::kWebSecurityStyleSecure);
+      response->SetSecurityStyle(blink::SecurityStyle::kSecure);
     else
-      response->SetSecurityStyle(blink::kWebSecurityStyleInsecure);
+      response->SetSecurityStyle(blink::SecurityStyle::kInsecure);
     return;
   }
 
   // The resource loader does not provide a guarantee that requests always have
-  // security info (such as a certificate) attached. Use WebSecurityStyleUnknown
+  // security info (such as a certificate) attached. Use SecurityStyleUnknown
   // in this case where there isn't enough information to be useful.
   if (!head.ssl_info.has_value()) {
-    response->SetSecurityStyle(blink::kWebSecurityStyleUnknown);
+    response->SetSecurityStyle(blink::SecurityStyle::kUnknown);
     return;
   }
 
@@ -250,9 +250,9 @@
   }
 
   if (net::IsCertStatusError(head.cert_status)) {
-    response->SetSecurityStyle(blink::kWebSecurityStyleInsecure);
+    response->SetSecurityStyle(blink::SecurityStyle::kInsecure);
   } else {
-    response->SetSecurityStyle(blink::kWebSecurityStyleSecure);
+    response->SetSecurityStyle(blink::SecurityStyle::kSecure);
   }
 
   blink::WebURLResponse::SignedCertificateTimestampList sct_list(
@@ -263,7 +263,7 @@
 
   if (!ssl_info.cert) {
     NOTREACHED();
-    response->SetSecurityStyle(blink::kWebSecurityStyleUnknown);
+    response->SetSecurityStyle(blink::SecurityStyle::kUnknown);
     return;
   }
 
diff --git a/content/renderer/page_properties.cc b/content/renderer/page_properties.cc
deleted file mode 100644
index 45b5601..0000000
--- a/content/renderer/page_properties.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/page_properties.h"
-
-#include "content/renderer/compositor/compositor_dependencies.h"
-#include "content/renderer/render_widget_screen_metrics_emulator.h"
-#include "third_party/blink/public/platform/web_float_rect.h"
-#include "third_party/blink/public/platform/web_rect.h"
-
-namespace content {
-PageProperties::PageProperties(CompositorDependencies* compositor_deps)
-    : compositor_deps_(compositor_deps) {}
-PageProperties::~PageProperties() = default;
-
-CompositorDependencies* PageProperties::GetCompositorDependencies() {
-  return compositor_deps_;
-}
-
-}  // namespace content
diff --git a/content/renderer/page_properties.h b/content/renderer/page_properties.h
deleted file mode 100644
index 3097c26..0000000
--- a/content/renderer/page_properties.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_PAGE_PROPERTIES_H_
-#define CONTENT_RENDERER_PAGE_PROPERTIES_H_
-
-#include "content/common/content_export.h"
-#include "content/public/common/screen_info.h"
-
-namespace content {
-
-class CompositorDependencies;
-
-// This interface exposes "page global" concepts to child frames. Historically
-// such state was managed by the RenderView API. However RenderView also has
-// to be have as the WebViewClient as well as the IPC anchor for content. As
-// such it is hard to separate what APIs are needed by blink, IPC, and other
-// content renderer objects.
-//
-// Splitting out an explicit concept aligned with a "page" better fits the
-// abstractions and clarifies which APIs can be coupled.
-class CONTENT_EXPORT PageProperties {
- public:
-  explicit PageProperties(CompositorDependencies* compositor_deps);
-  ~PageProperties();
-
-  CompositorDependencies* GetCompositorDependencies();
-
- private:
-  CompositorDependencies* compositor_deps_ = nullptr;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_PAGE_PROPERTIES_H_
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 4b2e423..daf78e4 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -1513,7 +1513,7 @@
   // RenderFrame.
   render_view->render_widget_ = RenderWidget::CreateForFrame(
       params->main_frame_widget_routing_id, compositor_deps,
-      render_view->page_properties(), params->visual_properties.display_mode,
+      params->visual_properties.display_mode,
       /*is_undead=*/params->main_frame_routing_id == MSG_ROUTING_NONE,
       params->never_visible);
 
@@ -1722,7 +1722,7 @@
     // space/context.
     std::unique_ptr<RenderWidget> render_widget = RenderWidget::CreateForFrame(
         widget_params->routing_id, compositor_deps,
-        render_view->page_properties(), blink::mojom::DisplayMode::kUndefined,
+        blink::mojom::DisplayMode::kUndefined,
         /*is_undead=*/false, /*never_visible=*/false);
 
     // Non-owning pointer that is self-referencing and destroyed by calling
@@ -2170,7 +2170,6 @@
   RenderWidgetFullscreenPepper* widget = RenderWidgetFullscreenPepper::Create(
       fullscreen_widget_routing_id, std::move(show_callback),
       GetLocalRootRenderWidget()->compositor_deps(),
-      render_view()->page_properties(),
       GetLocalRootRenderWidget()->GetOriginalScreenInfo(), plugin,
       std::move(main_frame_url), std::move(widget_channel_receiver));
   // TODO(nick): The show() handshake seems like unnecessary complexity here,
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index bf3f42e8..e168f2a21 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -458,8 +458,8 @@
     : routing_id_(params.view_id),
       renderer_wide_named_frame_lookup_(
           params.renderer_wide_named_frame_lookup),
+      compositor_deps_(compositor_deps),
       webkit_preferences_(params.web_preferences),
-      page_properties_(compositor_deps),
       session_storage_namespace_id_(params.session_storage_namespace_id) {
   DCHECK(!session_storage_namespace_id_.empty())
       << "Session storage namespace must be populated.";
@@ -510,7 +510,7 @@
     // RenderWidget for a remote main frame.
     undead_render_widget_ = RenderWidget::CreateForFrame(
         params->main_frame_widget_routing_id, compositor_deps,
-        page_properties(), params->visual_properties.display_mode,
+        params->visual_properties.display_mode,
         /*is_undead=*/true, params->never_visible);
     undead_render_widget_->set_delegate(this);
     // We intentionally pass in a null webwidget since it is not needed
@@ -1437,8 +1437,7 @@
                      base::Unretained(creator_frame), opened_by_user_gesture);
 
   RenderViewImpl* view = RenderViewImpl::Create(
-      page_properties_.GetCompositorDependencies(), std::move(view_params),
-      std::move(show_callback),
+      compositor_deps_, std::move(view_params), std::move(show_callback),
       creator->GetTaskRunner(blink::TaskType::kInternalDefault));
 
   return view->webview();
@@ -1468,7 +1467,7 @@
 
   RenderWidget* popup_widget = RenderWidget::CreateForPopup(
       widget_routing_id, opener_render_widget->compositor_deps(),
-      page_properties(), blink::mojom::DisplayMode::kUndefined,
+      blink::mojom::DisplayMode::kUndefined,
       /*hidden=*/false,
       /*never_visible=*/false, std::move(widget_channel_receiver));
 
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index b1d9886..deed046 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -144,11 +144,6 @@
   // future].
   RenderWidget* GetWidget();
 
-  // Returns a |page_properties| interface. The lifetime is scoped to
-  // the RenderViewImpl.
-  PageProperties* page_properties() { return &page_properties_; }
-  const PageProperties* page_properties() const { return &page_properties_; }
-
   const WebPreferences& webkit_preferences() const {
     return webkit_preferences_;
   }
@@ -567,6 +562,10 @@
   // beyond the usual opener-relationship-based BrowsingInstance boundaries).
   const bool renderer_wide_named_frame_lookup_;
 
+  // Dependency injection for RenderWidget and compositing to inject behaviour
+  // and not depend on RenderThreadImpl in tests.
+  CompositorDependencies* const compositor_deps_;
+
   // Settings ------------------------------------------------------------------
 
   WebPreferences webkit_preferences_;
@@ -588,10 +587,6 @@
   // to be called.
   bool needs_preferred_size_update_ = true;
 
-  // Properties about the page that are of interest to subframes. These persist
-  // across main-frame navigations.
-  PageProperties page_properties_;
-
   // Loading state -------------------------------------------------------------
 
   // Timer used to delay the updating of nav state (see
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 7dce266..65b65ac 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -411,38 +411,34 @@
 std::unique_ptr<RenderWidget> RenderWidget::CreateForFrame(
     int32_t widget_routing_id,
     CompositorDependencies* compositor_deps,
-    PageProperties* page_properties,
     blink::mojom::DisplayMode display_mode,
     bool is_undead,
     bool never_visible) {
   if (g_create_render_widget_for_frame) {
     return g_create_render_widget_for_frame(
-        widget_routing_id, compositor_deps, page_properties, display_mode,
-        is_undead, never_visible, mojo::NullReceiver());
+        widget_routing_id, compositor_deps, display_mode, is_undead,
+        never_visible, mojo::NullReceiver());
   }
 
   return std::make_unique<RenderWidget>(
-      widget_routing_id, compositor_deps, page_properties, display_mode,
-      is_undead,
+      widget_routing_id, compositor_deps, display_mode, is_undead,
       /*hidden=*/true, never_visible, mojo::NullReceiver());
 }
 
 RenderWidget* RenderWidget::CreateForPopup(
     int32_t widget_routing_id,
     CompositorDependencies* compositor_deps,
-    PageProperties* page_properties,
     blink::mojom::DisplayMode display_mode,
     bool hidden,
     bool never_visible,
     mojo::PendingReceiver<mojom::Widget> widget_receiver) {
-  return new RenderWidget(widget_routing_id, compositor_deps, page_properties,
-                          display_mode, /*is_undead=*/false, hidden,
-                          never_visible, std::move(widget_receiver));
+  return new RenderWidget(widget_routing_id, compositor_deps, display_mode,
+                          /*is_undead=*/false, hidden, never_visible,
+                          std::move(widget_receiver));
 }
 
 RenderWidget::RenderWidget(int32_t widget_routing_id,
                            CompositorDependencies* compositor_deps,
-                           PageProperties* page_properties,
                            blink::mojom::DisplayMode display_mode,
                            bool is_undead,
                            bool hidden,
@@ -450,7 +446,6 @@
                            mojo::PendingReceiver<mojom::Widget> widget_receiver)
     : routing_id_(widget_routing_id),
       compositor_deps_(compositor_deps),
-      page_properties_(page_properties),
       is_hidden_(hidden),
       compositor_never_visible_(never_visible),
       display_mode_(display_mode),
@@ -460,7 +455,6 @@
       widget_receiver_(this, std::move(widget_receiver)) {
   DCHECK_NE(routing_id_, MSG_ROUTING_NONE);
   DCHECK(RenderThread::IsMainThread());
-  DCHECK(page_properties);
 
   // In tests there may not be a RenderThreadImpl.
   if (RenderThreadImpl::current()) {
@@ -1722,8 +1716,8 @@
 
   RenderFrameImpl* render_frame =
       RenderFrameImpl::FromWebFrame(GetFrameWidget()->LocalRoot());
-  // UpdateSurfaceAndScreenInfo() changes PageProperties including the device
-  // scale factor, which changes PreferCompositingToLCDText decisions.
+  // UpdateSurfaceAndScreenInfo() changes properties including the device scale
+  // factor, which changes PreferCompositingToLCDText decisions.
   // TODO(danakj): Do this in UpdateSurfaceAndScreenInfo? But requires a Resize
   // to happen after (see comment on
   // SetPreferCompositingToLCDTextEnabledOnRenderView).
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index cd546b6b..670f655 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -42,7 +42,6 @@
 #include "content/renderer/input/render_widget_input_handler.h"
 #include "content/renderer/input/render_widget_input_handler_delegate.h"
 #include "content/renderer/mouse_lock_dispatcher.h"
-#include "content/renderer/page_properties.h"
 #include "content/renderer/render_widget_delegate.h"
 #include "content/renderer/render_widget_mouse_lock_dispatcher.h"
 #include "content/renderer/render_widget_screen_metrics_emulator_delegate.h"
@@ -169,7 +168,6 @@
  public:
   RenderWidget(int32_t widget_routing_id,
                CompositorDependencies* compositor_deps,
-               PageProperties* page_properties,
                blink::mojom::DisplayMode display_mode,
                bool is_undead,
                bool hidden,
@@ -194,7 +192,6 @@
   using CreateRenderWidgetFunction = std::unique_ptr<RenderWidget> (*)(
       int32_t,
       CompositorDependencies*,
-      PageProperties*,
       blink::mojom::DisplayMode display_mode,
       bool is_undead,
       bool never_visible,
@@ -210,7 +207,6 @@
   static std::unique_ptr<RenderWidget> CreateForFrame(
       int32_t widget_routing_id,
       CompositorDependencies* compositor_deps,
-      PageProperties* page_properties,
       blink::mojom::DisplayMode display_mode,
       bool is_undead,
       bool never_visible);
@@ -223,7 +219,6 @@
   static RenderWidget* CreateForPopup(
       int32_t widget_routing_id,
       CompositorDependencies* compositor_deps,
-      PageProperties* page_properties,
       blink::mojom::DisplayMode display_mode,
       bool hidden,
       bool never_visible,
@@ -926,11 +921,8 @@
   // a RenderViewImpl.
   RenderWidgetDelegate* delegate_ = nullptr;
 
-  // Contains properties that are global to a whole page. This is populated in
-  // all RenderWidgets regardless of whether they are main frame or child
-  // frame widgets.
-  PageProperties* const page_properties_;
-
+  // Wraps the LayerTreeHost, providing clients for it with the ability to
+  // outlive RenderWidget during shutdown and keep the client pointers valid.
   std::unique_ptr<LayerTreeView> layer_tree_view_;
   // This is valid while |layer_tree_view_| is valid.
   cc::LayerTreeHost* layer_tree_host_ = nullptr;
diff --git a/content/renderer/render_widget_fullscreen_pepper.cc b/content/renderer/render_widget_fullscreen_pepper.cc
index 40953e4..d7839cc 100644
--- a/content/renderer/render_widget_fullscreen_pepper.cc
+++ b/content/renderer/render_widget_fullscreen_pepper.cc
@@ -275,7 +275,6 @@
     int32_t routing_id,
     RenderWidget::ShowCallback show_callback,
     CompositorDependencies* compositor_deps,
-    PageProperties* page_properties,
     const ScreenInfo& screen_info,
     PepperPluginInstanceImpl* plugin,
     const blink::WebURL& local_main_frame_url,
@@ -283,8 +282,7 @@
   DCHECK_NE(MSG_ROUTING_NONE, routing_id);
   DCHECK(show_callback);
   RenderWidgetFullscreenPepper* widget = new RenderWidgetFullscreenPepper(
-      routing_id, compositor_deps, page_properties, plugin,
-      std::move(widget_receiver));
+      routing_id, compositor_deps, plugin, std::move(widget_receiver));
   widget->InitForPepperFullscreen(
       std::move(show_callback), new PepperWidget(widget, local_main_frame_url),
       screen_info);
@@ -294,12 +292,10 @@
 RenderWidgetFullscreenPepper::RenderWidgetFullscreenPepper(
     int32_t routing_id,
     CompositorDependencies* compositor_deps,
-    PageProperties* page_properties,
     PepperPluginInstanceImpl* plugin,
     mojo::PendingReceiver<mojom::Widget> widget_receiver)
     : RenderWidget(routing_id,
                    compositor_deps,
-                   page_properties,
                    /*display_mode=*/blink::mojom::DisplayMode::kUndefined,
                    /*is_undead=*/false,
                    /*hidden=*/false,
diff --git a/content/renderer/render_widget_fullscreen_pepper.h b/content/renderer/render_widget_fullscreen_pepper.h
index 772716f0..04dae968 100644
--- a/content/renderer/render_widget_fullscreen_pepper.h
+++ b/content/renderer/render_widget_fullscreen_pepper.h
@@ -37,7 +37,6 @@
       int32_t routing_id,
       RenderWidget::ShowCallback show_callback,
       CompositorDependencies* compositor_deps,
-      PageProperties* page_properties,
       const ScreenInfo& screen_info,
       PepperPluginInstanceImpl* plugin,
       const blink::WebURL& local_main_frame_url,
@@ -63,7 +62,6 @@
   RenderWidgetFullscreenPepper(
       int32_t routing_id,
       CompositorDependencies* compositor_deps,
-      PageProperties* page_properties,
       PepperPluginInstanceImpl* plugin,
       mojo::PendingReceiver<mojom::Widget> widget_receiver);
   ~RenderWidgetFullscreenPepper() override;
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc
index 695ee28..123a258 100644
--- a/content/renderer/render_widget_unittest.cc
+++ b/content/renderer/render_widget_unittest.cc
@@ -169,11 +169,9 @@
 class InteractiveRenderWidget : public RenderWidget {
  public:
   InteractiveRenderWidget(CompositorDependencies* compositor_deps,
-                          PageProperties* page_properties,
                           const ScreenInfo& screen_info)
       : RenderWidget(++next_routing_id_,
                      compositor_deps,
-                     page_properties,
                      blink::mojom::DisplayMode::kUndefined,
                      /*is_undead=*/false,
                      /*is_hidden=*/false,
@@ -255,11 +253,9 @@
 
 class RenderWidgetUnittest : public testing::Test {
  public:
-  RenderWidgetUnittest() : page_properties_(&compositor_deps_) {}
-
   void SetUp() override {
-    widget_ = std::make_unique<InteractiveRenderWidget>(
-        &compositor_deps_, &page_properties_, ScreenInfo());
+    widget_ = std::make_unique<InteractiveRenderWidget>(&compositor_deps_,
+                                                        ScreenInfo());
   }
 
   void TearDown() override {
@@ -282,7 +278,6 @@
   MockRenderProcess render_process_;
   MockRenderThread render_thread_;
   FakeCompositorDependencies compositor_deps_;
-  PageProperties page_properties_;
   std::unique_ptr<InteractiveRenderWidget> widget_;
   base::HistogramTester histogram_tester_;
 };
diff --git a/content/test/web_test_support.cc b/content/test/web_test_support.cc
index ee79a73..c9e4dee9 100644
--- a/content/test/web_test_support.cc
+++ b/content/test/web_test_support.cc
@@ -91,13 +91,12 @@
 std::unique_ptr<RenderWidget> CreateRenderWidgetForFrame(
     int32_t routing_id,
     CompositorDependencies* compositor_deps,
-    PageProperties* page_properties,
     blink::mojom::DisplayMode display_mode,
     bool swapped_out,
     bool never_visible,
     mojo::PendingReceiver<mojom::Widget> widget_receiver) {
   return std::make_unique<test_runner::WebWidgetTestProxy>(
-      routing_id, compositor_deps, page_properties, display_mode, swapped_out,
+      routing_id, compositor_deps, display_mode, swapped_out,
       /*hidden=*/true, never_visible, std::move(widget_receiver));
 }
 
diff --git a/google_apis/gaia/gaia_auth_util.h b/google_apis/gaia/gaia_auth_util.h
index a8c60d8..cc16fb645 100644
--- a/google_apis/gaia/gaia_auth_util.h
+++ b/google_apis/gaia/gaia_auth_util.h
@@ -18,7 +18,7 @@
 struct ListedAccount {
   // The account's ID, as per Chrome, will be determined in the
   // CookieManagerService.
-  // TODO(triploblastic): Rename the id field to account_id.
+  // TODO(https://crbug.com/1010878): Rename the id field to account_id.
   CoreAccountId id;
   std::string email;
   std::string gaia_id;
diff --git a/headless/lib/browser/headless_request_context_manager.cc b/headless/lib/browser/headless_request_context_manager.cc
index 07adf5b..3efed09 100644
--- a/headless/lib/browser/headless_request_context_manager.cc
+++ b/headless/lib/browser/headless_request_context_manager.cc
@@ -113,8 +113,8 @@
       ::network::mojom::NetworkContextParams* network_context_params) {
     DCHECK(task_runner_->RunsTasksInCurrentSequence());
     DCHECK(!proxy_config_client_);
-    network_context_params->proxy_config_client_request =
-        mojo::MakeRequest(&proxy_config_client_);
+    network_context_params->proxy_config_client_receiver =
+        proxy_config_client_.BindNewPipeAndPassReceiver();
     poller_binding_.Bind(
         mojo::MakeRequest(&network_context_params->proxy_config_poller_client));
     net::ProxyConfigWithAnnotation proxy_config;
@@ -151,7 +151,7 @@
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   std::unique_ptr<net::ProxyConfigService> proxy_config_service_;
   mojo::Binding<::network::mojom::ProxyConfigPollerClient> poller_binding_;
-  ::network::mojom::ProxyConfigClientPtr proxy_config_client_;
+  mojo::Remote<::network::mojom::ProxyConfigClient> proxy_config_client_;
 
   DISALLOW_COPY_AND_ASSIGN(HeadlessProxyConfigMonitor);
 };
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc
index 86f4d81..87c46787 100644
--- a/headless/lib/browser/headless_web_contents_impl.cc
+++ b/headless/lib/browser/headless_web_contents_impl.cc
@@ -73,7 +73,7 @@
 #if !defined(CHROME_MULTIPLE_DLL_CHILD)
   // Return the security style of the given |web_contents|, populating
   // |security_style_explanations| to explain why the SecurityStyle was chosen.
-  blink::WebSecurityStyle GetSecurityStyle(
+  blink::SecurityStyle GetSecurityStyle(
       content::WebContents* web_contents,
       content::SecurityStyleExplanations* security_style_explanations)
       override {
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator_egtest.mm
index d684ece..a0d658e 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator_egtest.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator_egtest.mm
@@ -172,12 +172,21 @@
 
 // Returns YES if the keyboard is docked at the bottom. NO otherwise.
 BOOL IsKeyboardDockedForLayout(UIView* layout) {
-  CGRect keyboardFrameInWindow = [layout.window convertRect:layout.bounds
-                                                   fromView:layout];
   CGRect windowBounds = layout.window.bounds;
-  CGFloat maxY = CGRectGetMaxY(keyboardFrameInWindow);
+  UIView* viewToCompare = layout;
+  while (viewToCompare &&
+         viewToCompare.bounds.size.height < windowBounds.size.height) {
+    CGRect keyboardFrameInWindow =
+        [viewToCompare.window convertRect:viewToCompare.bounds
+                                 fromView:viewToCompare];
 
-  return [@(maxY) isEqualToNumber:@(windowBounds.size.height)];
+    CGFloat maxY = CGRectGetMaxY(keyboardFrameInWindow);
+    if ([@(maxY) isEqualToNumber:@(windowBounds.size.height)]) {
+      return YES;
+    }
+    viewToCompare = viewToCompare.superview;
+  }
+  return NO;
 }
 
 // Undocks and split the keyboard by swiping it up. Does nothing if already
diff --git a/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.h b/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.h
index 7f71ede..fcbfc4c 100644
--- a/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.h
+++ b/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.h
@@ -34,4 +34,11 @@
 
 @end
 
+@interface QRScannerViewController (TestingAdditions)
+
+// Simulates VoiceOver being enabled for this Scanner.
+- (void)overrideVoiceOverCheck:(BOOL)overrideVoiceOverCheck;
+
+@end
+
 #endif  // IOS_CHROME_BROWSER_UI_QR_SCANNER_QR_SCANNER_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.mm b/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.mm
index 010dbbf..6159735 100644
--- a/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.mm
+++ b/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.mm
@@ -31,11 +31,14 @@
 
 @property(nonatomic, readwrite, weak) id<LoadQueryCommands> queryLoader;
 
+// Whether VoiceOver detection has been overridden.
+@property(nonatomic, assign) BOOL voiceOverCheckOverridden;
+
 @end
 
 @implementation QRScannerViewController
 
-#pragma mark Lifecycle
+#pragma mark - Lifecycle
 
 - (instancetype)
     initWithPresentationProvider:(id<ScannerPresenting>)presentationProvider
@@ -79,7 +82,7 @@
 #pragma mark - QRScannerCameraControllerDelegate
 
 - (void)receiveQRScannerResult:(NSString*)result loadImmediately:(BOOL)load {
-  if (UIAccessibilityIsVoiceOverRunning()) {
+  if ([self isVoiceOverActive]) {
     // Post a notification announcing that a code was scanned. QR scanner will
     // be dismissed when the UIAccessibilityAnnouncementDidFinishNotification is
     // received.
@@ -116,4 +119,17 @@
   }
 }
 
+#pragma mark - Private
+
+// Returns whether voice over is active.
+- (BOOL)isVoiceOverActive {
+  return UIAccessibilityIsVoiceOverRunning() || self.voiceOverCheckOverridden;
+}
+
+#pragma mark - Testing Additions
+
+- (void)overrideVoiceOverCheck:(BOOL)overrideVoiceOverCheck {
+  self.voiceOverCheckOverridden = overrideVoiceOverCheck;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller_egtest.mm b/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller_egtest.mm
index d20b2f8..88f315970 100644
--- a/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller_egtest.mm
+++ b/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller_egtest.mm
@@ -7,6 +7,7 @@
 #import <UIKit/UIKit.h>
 
 #include "base/ios/ios_util.h"
+#include "base/mac/foundation_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/strings/grit/components_strings.h"
@@ -145,6 +146,32 @@
 
 }  // namespace
 
+// Override a QRScannerViewController voice search check, simulating voice
+// search being enabled. This doesn't reset the previous value, don't use
+// nested.
+@interface ScopedQRScannerVoiceSearchOverride : NSObject
+@property(nonatomic, weak) QRScannerViewController* scanner;
+@end
+
+@implementation ScopedQRScannerVoiceSearchOverride
+
+- (instancetype)initWithQRScanner:(QRScannerViewController*)QRScanner {
+  self = [super init];
+  if (self) {
+    _scanner = QRScanner;
+    [_scanner overrideVoiceOverCheck:YES];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [_scanner overrideVoiceOverCheck:NO];
+}
+
+@end
+
+#pragma mark - Test Case
+
 @interface QRScannerViewControllerTestCase : ChromeTestCase {
   GURL _testURL;
   GURL _testURLEdited;
@@ -788,6 +815,56 @@
           isNotPresentedBy:[self currentViewController]];
 }
 
+// Test that the correct page is loaded if the scanner result is a URL which is
+// then manually edited when VoiceOver is enabled.
+- (void)testReceivingQRScannerURLResultWithVoiceOver {
+  id cameraControllerMock =
+      [self getCameraControllerMockWithAuthorizationStatus:
+                AVAuthorizationStatusAuthorized];
+  [self swizzleCameraController:cameraControllerMock];
+
+  // Open the QR scanner.
+  [self showQRScannerAndCheckLayoutWithCameraMock:cameraControllerMock];
+  [self callTorchAvailabilityChanged:YES];
+  [self assertQRScannerUIIsVisibleWithTorch:YES];
+
+  // Add override for the VoiceOver check.
+  QRScannerViewController* viewController =
+      base::mac::ObjCCast<QRScannerViewController>(
+          [[self currentViewController] presentedViewController]);
+  GREYAssertTrue(viewController, @"The QRScanner isn't presented.");
+  ScopedQRScannerVoiceSearchOverride* scopedOverride =
+      [[ScopedQRScannerVoiceSearchOverride alloc]
+          initWithQRScanner:viewController];
+
+  // Receive a scanned result from the camera.
+  [self addCameraControllerDismissalExpectations:cameraControllerMock];
+  [self callReceiveQRScannerResult:base::SysUTF8ToNSString(
+                                       _testURL.GetContent())];
+
+  // Fake the end of the VoiceOver announcement.
+  NSString* scannedAnnouncement = l10n_util::GetNSString(
+      IDS_IOS_SCANNER_SCANNED_ACCESSIBILITY_ANNOUNCEMENT);
+  [[NSNotificationCenter defaultCenter]
+      postNotificationName:UIAccessibilityAnnouncementDidFinishNotification
+                    object:nil
+                  userInfo:@{
+                    UIAccessibilityAnnouncementKeyStringValue :
+                        scannedAnnouncement
+                  }];
+
+  [self waitForModalOfClass:[QRScannerViewController class]
+       toDisappearFromAbove:[self currentViewController]];
+  [cameraControllerMock verify];
+
+  // Optionally edit the text in the omnibox before pressing return.
+  [self assertOmniboxIsVisibleWithText:_testURL.GetContent()];
+  TapKeyboardReturnKeyInOmniboxWithText(_testURL.GetContent());
+  [ChromeEarlGrey waitForWebStateContainingText:kTestURLResponse];
+
+  scopedOverride = nil;
+}
+
 // Test that the correct page is loaded if the scanner result is a URL.
 - (void)testReceivingQRScannerURLResult {
   [self doTestReceivingResult:_testURL.GetContent()
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
index 482b66f..5fc9c058 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
@@ -12,6 +12,7 @@
 #include "base/bind.h"
 #include "base/ios/ios_util.h"
 #include "base/mac/foundation_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #import "base/test/ios/wait_util.h"
@@ -274,6 +275,28 @@
   [chrome_test_util::BrowserCommandDispatcherForMainBVC() showReadingList];
 }
 
+// Adds 20 read and 20 unread entries to the model, opens the reading list menu
+// and enter edit mode.
+void AddLotOfEntriesAndEnterEdit() {
+  ReadingListModel* model = GetReadingListModel();
+  for (NSInteger index = 0; index < 10; index++) {
+    GURL url_to_be_added =
+        GURL(kReadURL + std::string("/") + base::NumberToString(index));
+    model->AddEntry(url_to_be_added, std::string(kReadTitle),
+                    reading_list::ADDED_VIA_CURRENT_APP);
+    model->SetReadStatus(url_to_be_added, true);
+  }
+  for (NSInteger index = 0; index < 10; index++) {
+    GURL url_to_be_added =
+        GURL(kUnreadURL + std::string("/") + base::NumberToString(index));
+    model->AddEntry(url_to_be_added, std::string(kReadTitle),
+                    reading_list::ADDED_VIA_CURRENT_APP);
+  }
+  OpenReadingList();
+
+  TapToolbarButtonWithID(kReadingListToolbarEditButtonID);
+}
+
 // Adds a read and an unread entry to the model, opens the reading list menu and
 // enter edit mode.
 void AddEntriesAndEnterEdit() {
@@ -872,6 +895,21 @@
   XCTAssertEqual((size_t)0, ModelReadSize(GetReadingListModel()));
 }
 
+// Marks all read entries as unread, when there is a lot of entries. This is to
+// prevent crbug.com/1013708 from regressing.
+- (void)testMarkAllUnreadLotOfEntry {
+  AddLotOfEntriesAndEnterEdit();
+
+  AssertToolbarMarkButtonText(IDS_IOS_READING_LIST_MARK_ALL_BUTTON);
+  TapToolbarButtonWithID(kReadingListToolbarMarkButtonID);
+
+  // Tap the action sheet.
+  TapContextMenuButtonWithA11yLabelID(
+      IDS_IOS_READING_LIST_MARK_ALL_UNREAD_ACTION);
+
+  AssertHeaderNotVisible(kReadHeader);
+}
+
 // Selects an unread entry and mark it as read.
 - (void)testMarkEntriesRead {
   AddEntriesAndEnterEdit();
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
index 82c5ab35..86eea8c0 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
@@ -667,6 +667,9 @@
                     toSection:(SectionIdentifier)toSection {
   // Reconfigure cells, allowing the custom actions to be updated.
   for (NSIndexPath* indexPath in sortedIndexPaths) {
+    if (![self.tableView cellForRowAtIndexPath:indexPath])
+      continue;
+
     [[self.tableViewModel itemAtIndexPath:indexPath]
         configureCell:[self.tableView cellForRowAtIndexPath:indexPath]
            withStyler:self.styler];
diff --git a/media/audio/win/audio_low_latency_input_win.cc b/media/audio/win/audio_low_latency_input_win.cc
index 8fc6929e..9c20b24 100644
--- a/media/audio/win/audio_low_latency_input_win.cc
+++ b/media/audio/win/audio_low_latency_input_win.cc
@@ -238,6 +238,15 @@
   if (started_)
     return;
 
+  // Check if the master volume level of the opened audio session is set to
+  // zero and store the information for a UMA histogram generated in Stop().
+  // Valid volume levels are in the range 0.0 to 1.0.
+  // See http://crbug.com/1014443 for details why this is needed.
+  if (GetVolume() == 0.0) {
+    DLOG(WARNING) << "Input audio session starts with zero volume";
+    audio_session_starts_at_zero_volume_ = true;
+  }
+
   if (device_id_ == AudioDeviceDescription::kLoopbackWithMuteDeviceId &&
       system_audio_volume_) {
     BOOL muted = false;
@@ -293,6 +302,10 @@
   if (!started_)
     return;
 
+  // Only upload UMA histogram for the case when AGC is enabled, i.e., for
+  // WebRTC based audio input streams.
+  const bool add_uma_histogram = GetAutomaticGainControl();
+
   // We have muted system audio for capturing, so we need to unmute it when
   // capturing stops.
   if (device_id_ == AudioDeviceDescription::kLoopbackWithMuteDeviceId &&
@@ -325,6 +338,16 @@
     capture_thread_.reset();
   }
 
+  // Upload UMA histogram to track down possible issue that can lead to a
+  // "no audio" state. See http://crbug.com/1014443.
+  if (add_uma_histogram) {
+    base::UmaHistogramBoolean("Media.Audio.InputVolumeStartsAtZeroWin",
+                              audio_session_starts_at_zero_volume_);
+    DVLOG(1) << "Media.Audio.InputVolumeStartsAtZeroWin: "
+             << audio_session_starts_at_zero_volume_;
+    audio_session_starts_at_zero_volume_ = false;
+  }
+
   started_ = false;
   sink_ = nullptr;
 }
@@ -358,7 +381,6 @@
 }
 
 void WASAPIAudioInputStream::SetVolume(double volume) {
-  DVLOG(1) << "SetVolume(volume=" << volume << ")";
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_GE(volume, 0.0);
   DCHECK_LE(volume, 1.0);
diff --git a/media/audio/win/audio_low_latency_input_win.h b/media/audio/win/audio_low_latency_input_win.h
index 8ec4f53..d28cca49 100644
--- a/media/audio/win/audio_low_latency_input_win.h
+++ b/media/audio/win/audio_low_latency_input_win.h
@@ -292,6 +292,10 @@
   UINT64 total_lost_frames_ = 0;
   UINT64 largest_glitch_frames_ = 0;
 
+  // Enabled if the volume level of the audio session is set to zero when the
+  // session starts. Utilized in UMA histogram.
+  bool audio_session_starts_at_zero_volume_ = false;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(WASAPIAudioInputStream);
diff --git a/media/gpu/v4l2/BUILD.gn b/media/gpu/v4l2/BUILD.gn
index 7138d60..9c437c6 100644
--- a/media/gpu/v4l2/BUILD.gn
+++ b/media/gpu/v4l2/BUILD.gn
@@ -51,6 +51,10 @@
     "v4l2_vda_helpers.h",
     "v4l2_video_decode_accelerator.cc",
     "v4l2_video_decode_accelerator.h",
+    "v4l2_video_decoder_backend.cc",
+    "v4l2_video_decoder_backend.h",
+    "v4l2_video_decoder_backend_stateless.cc",
+    "v4l2_video_decoder_backend_stateless.h",
     "v4l2_video_encode_accelerator.cc",
     "v4l2_video_encode_accelerator.h",
     "v4l2_vp8_accelerator.cc",
diff --git a/media/gpu/v4l2/v4l2_slice_video_decoder.cc b/media/gpu/v4l2/v4l2_slice_video_decoder.cc
index 3819b170..1cd0639 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decoder.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decoder.cc
@@ -4,10 +4,6 @@
 
 #include "media/gpu/v4l2/v4l2_slice_video_decoder.h"
 
-#include <fcntl.h>
-#include <linux/media.h>
-#include <sys/ioctl.h>
-
 #include <algorithm>
 
 #include "base/bind.h"
@@ -15,18 +11,12 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/task/post_task.h"
-#include "media/base/scopedfd_helper.h"
 #include "media/base/video_util.h"
-#include "media/gpu/accelerated_video_decoder.h"
 #include "media/gpu/chromeos/fourcc.h"
 #include "media/gpu/gpu_video_decode_accelerator_helpers.h"
 #include "media/gpu/linux/dmabuf_video_frame_pool.h"
 #include "media/gpu/macros.h"
-#include "media/gpu/v4l2/v4l2_h264_accelerator.h"
-#include "media/gpu/v4l2/v4l2_h264_accelerator_legacy.h"
-#include "media/gpu/v4l2/v4l2_vp8_accelerator.h"
-#include "media/gpu/v4l2/v4l2_vp8_accelerator_legacy.h"
-#include "media/gpu/v4l2/v4l2_vp9_accelerator.h"
+#include "media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h"
 
 namespace media {
 
@@ -40,9 +30,6 @@
 constexpr size_t kInputBufferMaxSizeFor4k = 4 * kInputBufferMaxSizeFor1080p;
 constexpr size_t kNumInputBuffers = 16;
 
-// Size of the timestamp cache, needs to be large enough for frame-reordering.
-constexpr size_t kTimestampCacheSize = 128;
-
 // Input format V4L2 fourccs this class supports.
 constexpr uint32_t kSupportedInputFourccs[] = {
     V4L2_PIX_FMT_H264_SLICE,
@@ -52,63 +39,6 @@
 
 }  // namespace
 
-V4L2SliceVideoDecoder::DecodeRequest::DecodeRequest(
-    scoped_refptr<DecoderBuffer> buf,
-    DecodeCB cb,
-    int32_t id)
-    : buffer(std::move(buf)), decode_cb(std::move(cb)), bitstream_id(id) {}
-
-V4L2SliceVideoDecoder::DecodeRequest::DecodeRequest(DecodeRequest&&) = default;
-V4L2SliceVideoDecoder::DecodeRequest& V4L2SliceVideoDecoder::DecodeRequest::
-operator=(DecodeRequest&&) = default;
-
-V4L2SliceVideoDecoder::DecodeRequest::~DecodeRequest() = default;
-
-struct V4L2SliceVideoDecoder::OutputRequest {
-  enum OutputRequestType {
-    // The surface to be outputted.
-    kSurface,
-    // The fence to indicate the flush request.
-    kFlushFence,
-    // The fence to indicate resolution change request.
-    kChangeResolutionFence,
-  };
-
-  // The type of the request.
-  const OutputRequestType type;
-  // The surface to be outputted.
-  scoped_refptr<V4L2DecodeSurface> surface;
-  // The timestamp of the output frame. Because a surface might be outputted
-  // multiple times with different timestamp, we need to store timestamp out of
-  // surface.
-  base::TimeDelta timestamp;
-
-  static OutputRequest Surface(scoped_refptr<V4L2DecodeSurface> s,
-                               base::TimeDelta t) {
-    return OutputRequest(std::move(s), t);
-  }
-
-  static OutputRequest FlushFence() { return OutputRequest(kFlushFence); }
-
-  static OutputRequest ChangeResolutionFence() {
-    return OutputRequest(kChangeResolutionFence);
-  }
-
-  bool IsReady() const {
-    return (type != OutputRequestType::kSurface) || surface->decoded();
-  }
-
-  // Allow move, but not copy.
-  OutputRequest(OutputRequest&&) = default;
-
- private:
-  OutputRequest(scoped_refptr<V4L2DecodeSurface> s, base::TimeDelta t)
-      : type(kSurface), surface(std::move(s)), timestamp(t) {}
-  explicit OutputRequest(OutputRequestType t) : type(t) {}
-
-  DISALLOW_COPY_AND_ASSIGN(OutputRequest);
-};
-
 // static
 std::unique_ptr<VideoDecoder> V4L2SliceVideoDecoder::Create(
     scoped_refptr<base::SequencedTaskRunner> client_task_runner,
@@ -149,7 +79,6 @@
       get_pool_cb_(std::move(get_pool_cb)),
       client_task_runner_(std::move(client_task_runner)),
       decoder_task_runner_(std::move(decoder_task_runner)),
-      bitstream_id_to_timestamp_(kTimestampCacheSize),
       weak_this_factory_(this) {
   DETACH_FROM_SEQUENCE(client_sequence_checker_);
   DETACH_FROM_SEQUENCE(decoder_sequence_checker_);
@@ -161,7 +90,6 @@
   // We might be called from either the client or the decoder sequence.
   DETACH_FROM_SEQUENCE(client_sequence_checker_);
   DETACH_FROM_SEQUENCE(decoder_sequence_checker_);
-  DCHECK(requests_.empty());
   VLOGF(2);
 }
 
@@ -209,9 +137,7 @@
   DVLOGF(2);
 
   // Call all pending decode callback.
-  ClearPendingRequests(DecodeStatus::ABORTED);
-
-  avd_ = nullptr;
+  backend_->ClearPendingRequests(DecodeStatus::ABORTED);
 
   // Stop and Destroy device.
   StopStreamV4L2Queue();
@@ -223,12 +149,6 @@
     output_queue_->DeallocateBuffers();
     output_queue_ = nullptr;
   }
-  DCHECK(surfaces_at_device_.empty());
-
-  if (supports_requests_) {
-    requests_ = {};
-    media_fd_.reset();
-  }
 
   weak_this_factory_.InvalidateWeakPtrs();
 
@@ -269,14 +189,6 @@
   DCHECK(state_ == State::kUninitialized || state_ == State::kDecoding);
   DVLOGF(3);
 
-  if (!output_request_queue_.empty() || flush_cb_ || current_decode_request_ ||
-      !decode_request_queue_.empty()) {
-    VLOGF(1) << "Should not call Initialize() during pending decode";
-    client_task_runner_->PostTask(FROM_HERE,
-                                  base::BindOnce(std::move(init_cb), false));
-    return;
-  }
-
   // Reset V4L2 device and queue if reinitializing decoder.
   if (state_ != State::kUninitialized) {
     if (!StopStreamV4L2Queue()) {
@@ -298,10 +210,9 @@
       return;
     }
 
-    if (avd_) {
-      avd_->Reset();
-      avd_ = nullptr;
-    }
+    if (backend_)
+      backend_ = nullptr;
+
     SetState(State::kUninitialized);
   }
 
@@ -332,41 +243,6 @@
     return;
   }
 
-  if (!CheckRequestAPISupport()) {
-    VPLOGF(1) << "Failed to check request api support.";
-    client_task_runner_->PostTask(FROM_HERE,
-                                  base::BindOnce(std::move(init_cb), false));
-    return;
-  }
-
-  // Create codec-specific AcceleratedVideoDecoder.
-  // TODO(akahuang): Check the profile is supported.
-  if (profile >= H264PROFILE_MIN && profile <= H264PROFILE_MAX) {
-    if (supports_requests_) {
-      avd_.reset(new H264Decoder(
-          std::make_unique<V4L2H264Accelerator>(this, device_.get())));
-    } else {
-      avd_.reset(new H264Decoder(
-          std::make_unique<V4L2LegacyH264Accelerator>(this, device_.get())));
-    }
-  } else if (profile >= VP8PROFILE_MIN && profile <= VP8PROFILE_MAX) {
-    if (supports_requests_) {
-      avd_.reset(new VP8Decoder(
-          std::make_unique<V4L2VP8Accelerator>(this, device_.get())));
-    } else {
-      avd_.reset(new VP8Decoder(
-          std::make_unique<V4L2LegacyVP8Accelerator>(this, device_.get())));
-    }
-  } else if (profile >= VP9PROFILE_MIN && profile <= VP9PROFILE_MAX) {
-    avd_.reset(new VP9Decoder(
-        std::make_unique<V4L2VP9Accelerator>(this, device_.get())));
-  } else {
-    VLOGF(1) << "Unsupported profile " << GetProfileName(profile);
-    client_task_runner_->PostTask(FROM_HERE,
-                                  base::BindOnce(std::move(init_cb), false));
-    return;
-  }
-
   needs_bitstream_conversion_ = (config.codec() == kCodecH264);
   pixel_aspect_ratio_ = config.GetPixelAspectRatio();
 
@@ -380,6 +256,15 @@
     return;
   }
 
+  // Create the backend (only stateless API supported as of now).
+  backend_ = std::make_unique<V4L2StatelessVideoDecoderBackend>(
+      this, device_, frame_pool_, profile, decoder_task_runner_);
+  if (!backend_->Initialize()) {
+    client_task_runner_->PostTask(FROM_HERE,
+                                  base::BindOnce(std::move(init_cb), false));
+    return;
+  }
+
   // Setup input format.
   if (!SetupInputFormat(input_format_fourcc)) {
     VLOGF(1) << "Failed to setup input format.";
@@ -410,12 +295,6 @@
     return;
   }
 
-  if (supports_requests_ && !AllocateRequests()) {
-    client_task_runner_->PostTask(FROM_HERE,
-                                  base::BindOnce(std::move(init_cb), false));
-    return;
-  }
-
   // Call init_cb
   output_cb_ = output_cb;
   SetState(State::kDecoding);
@@ -423,62 +302,6 @@
                                 base::BindOnce(std::move(init_cb), true));
 }
 
-bool V4L2SliceVideoDecoder::CheckRequestAPISupport() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DVLOGF(3);
-
-  struct v4l2_requestbuffers reqbufs;
-  memset(&reqbufs, 0, sizeof(reqbufs));
-  reqbufs.count = 0;
-  reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-  reqbufs.memory = V4L2_MEMORY_MMAP;
-  if (device_->Ioctl(VIDIOC_REQBUFS, &reqbufs) != 0) {
-    VPLOGF(1) << "VIDIOC_REQBUFS ioctl failed.";
-    return false;
-  }
-  if (reqbufs.capabilities & V4L2_BUF_CAP_SUPPORTS_REQUESTS) {
-    supports_requests_ = true;
-    VLOGF(1) << "Using request API.";
-    DCHECK(!media_fd_.is_valid());
-    // Let's try to open the media device
-    // TODO(crbug.com/985230): remove this hardcoding, replace with V4L2Device
-    // integration.
-    int media_fd = open("/dev/media-dec0", O_RDWR, 0);
-    if (media_fd < 0) {
-      VPLOGF(1) << "Failed to open media device.";
-      return false;
-    }
-    media_fd_ = base::ScopedFD(media_fd);
-  } else {
-    VLOGF(1) << "Using config store.";
-  }
-
-  return true;
-}
-
-bool V4L2SliceVideoDecoder::AllocateRequests() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DVLOGF(3);
-
-  DCHECK(requests_.empty());
-
-  for (size_t i = 0; i < input_queue_->AllocatedBuffersCount(); i++) {
-    int request_fd;
-
-    int ret = HANDLE_EINTR(
-        ioctl(media_fd_.get(), MEDIA_IOC_REQUEST_ALLOC, &request_fd));
-    if (ret < 0) {
-      VPLOGF(1) << "Failed to create request: ";
-      return false;
-     }
-
-    requests_.push(base::ScopedFD(request_fd));
-  }
-  DCHECK_EQ(requests_.size(), input_queue_->AllocatedBuffersCount());
-
-  return true;
-}
-
 bool V4L2SliceVideoDecoder::SetupInputFormat(uint32_t input_format_fourcc) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
   DCHECK_EQ(state_, State::kUninitialized);
@@ -610,7 +433,7 @@
   DVLOGF(3);
 
   // Call all pending decode callback.
-  ClearPendingRequests(DecodeStatus::ABORTED);
+  backend_->ClearPendingRequests(DecodeStatus::ABORTED);
 
   // Streamoff V4L2 queues to drop input and output buffers.
   // If the queues are streaming before reset, then we need to start streaming
@@ -627,33 +450,6 @@
   client_task_runner_->PostTask(FROM_HERE, std::move(closure));
 }
 
-void V4L2SliceVideoDecoder::ClearPendingRequests(DecodeStatus status) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DVLOGF(3);
-
-  if (avd_)
-    avd_->Reset();
-
-  // Clear output_request_queue_.
-  while (!output_request_queue_.empty())
-    output_request_queue_.pop();
-
-  if (flush_cb_)
-    RunDecodeCB(std::move(flush_cb_), status);
-
-  // Clear current_decode_request_ and decode_request_queue_.
-  if (current_decode_request_) {
-    RunDecodeCB(std::move(current_decode_request_->decode_cb), status);
-    current_decode_request_ = base::nullopt;
-  }
-
-  while (!decode_request_queue_.empty()) {
-    auto request = std::move(decode_request_queue_.front());
-    decode_request_queue_.pop();
-    RunDecodeCB(std::move(request.decode_cb), status);
-  }
-}
-
 void V4L2SliceVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
                                    DecodeCB decode_cb) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
@@ -676,345 +472,8 @@
   }
 
   const int32_t bitstream_id = bitstream_id_generator_.GetNextBitstreamId();
-
-  if (!buffer->end_of_stream()) {
-    bitstream_id_to_timestamp_.Put(bitstream_id, buffer->timestamp());
-  }
-
-  decode_request_queue_.push(
-      DecodeRequest(std::move(buffer), std::move(decode_cb), bitstream_id));
-
-  // If we are already decoding, then we don't need to pump again.
-  if (!current_decode_request_)
-    PumpDecodeTask();
-}
-
-void V4L2SliceVideoDecoder::PumpDecodeTask() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DVLOGF(3) << "state_:" << static_cast<int>(state_)
-            << " Number of Decode requests: " << decode_request_queue_.size();
-
-  if (state_ != State::kDecoding)
-    return;
-
-  pause_reason_ = PauseReason::kNone;
-  while (true) {
-    switch (avd_->Decode()) {
-      case AcceleratedVideoDecoder::kAllocateNewSurfaces:
-        DVLOGF(3) << "Need to change resolution. Pause decoding.";
-        SetState(State::kFlushing);
-
-        output_request_queue_.push(OutputRequest::ChangeResolutionFence());
-        PumpOutputSurfaces();
-        return;
-
-      case AcceleratedVideoDecoder::kRanOutOfStreamData:
-        // Current decode request is finished processing.
-        if (current_decode_request_) {
-          DCHECK(current_decode_request_->decode_cb);
-          RunDecodeCB(std::move(current_decode_request_->decode_cb),
-                      DecodeStatus::OK);
-          current_decode_request_ = base::nullopt;
-        }
-
-        // Process next decodee request.
-        if (decode_request_queue_.empty())
-          return;
-        current_decode_request_ = std::move(decode_request_queue_.front());
-        decode_request_queue_.pop();
-
-        if (current_decode_request_->buffer->end_of_stream()) {
-          if (!avd_->Flush()) {
-            VLOGF(1) << "Failed flushing the decoder.";
-            SetState(State::kError);
-            return;
-          }
-          // Put the decoder in an idle state, ready to resume.
-          avd_->Reset();
-
-          SetState(State::kFlushing);
-          DCHECK(!flush_cb_);
-          flush_cb_ = std::move(current_decode_request_->decode_cb);
-
-          output_request_queue_.push(OutputRequest::FlushFence());
-          PumpOutputSurfaces();
-          current_decode_request_ = base::nullopt;
-          return;
-        }
-
-        avd_->SetStream(current_decode_request_->bitstream_id,
-                        *current_decode_request_->buffer);
-        break;
-
-      case AcceleratedVideoDecoder::kRanOutOfSurfaces:
-        DVLOGF(3) << "Ran out of surfaces. Resume when buffer is returned.";
-        pause_reason_ = PauseReason::kRanOutOfSurfaces;
-        return;
-
-      case AcceleratedVideoDecoder::kNeedContextUpdate:
-        DVLOGF(3) << "Awaiting context update";
-        pause_reason_ = PauseReason::kWaitSubFrameDecoded;
-        return;
-
-      case AcceleratedVideoDecoder::kDecodeError:
-        DVLOGF(3) << "Error decoding stream";
-        SetState(State::kError);
-        return;
-
-      case AcceleratedVideoDecoder::kTryAgain:
-        NOTREACHED() << "Should not reach here unless this class accepts "
-                        "encrypted streams.";
-        DVLOGF(4) << "No key for decoding stream.";
-        SetState(State::kError);
-        return;
-    }
-  }
-}
-
-void V4L2SliceVideoDecoder::PumpOutputSurfaces() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DVLOGF(3) << "state_: " << static_cast<int>(state_)
-            << " Number of display surfaces: " << output_request_queue_.size();
-
-  bool resume_decode = false;
-  while (!output_request_queue_.empty()) {
-    if (!output_request_queue_.front().IsReady()) {
-      DVLOGF(3) << "The first surface is not ready yet.";
-      break;
-    }
-
-    OutputRequest request = std::move(output_request_queue_.front());
-    output_request_queue_.pop();
-    switch (request.type) {
-      case OutputRequest::kFlushFence:
-        DCHECK(output_request_queue_.empty());
-        DVLOGF(2) << "Flush finished.";
-        RunDecodeCB(std::move(flush_cb_), DecodeStatus::OK);
-        resume_decode = true;
-        break;
-
-      case OutputRequest::kChangeResolutionFence:
-        DCHECK(output_request_queue_.empty());
-        if (!ChangeResolution()) {
-          SetState(State::kError);
-          return;
-        }
-        resume_decode = true;
-        break;
-
-      case OutputRequest::kSurface:
-        scoped_refptr<V4L2DecodeSurface> surface = std::move(request.surface);
-
-        DCHECK(surface->video_frame());
-        RunOutputCB(surface->video_frame(), surface->visible_rect(),
-                    request.timestamp);
-        break;
-    }
-  }
-
-  if (resume_decode) {
-    SetState(State::kDecoding);
-    decoder_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&V4L2SliceVideoDecoder::PumpDecodeTask, weak_this_));
-  }
-}
-
-bool V4L2SliceVideoDecoder::ChangeResolution() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DCHECK_EQ(state_, State::kFlushing);
-  // We change resolution after outputting all pending surfaces, there should
-  // be no V4L2DecodeSurface left.
-  DCHECK(surfaces_at_device_.empty());
-  DCHECK_EQ(input_queue_->QueuedBuffersCount(), 0u);
-  DCHECK_EQ(output_queue_->QueuedBuffersCount(), 0u);
-
-  DCHECK(output_request_queue_.empty());
-  if (!StopStreamV4L2Queue())
-    return false;
-
-  // Set output format with the new resolution.
-  gfx::Size pic_size = avd_->GetPicSize();
-  DCHECK(!pic_size.IsEmpty());
-  DVLOGF(3) << "Change resolution to " << pic_size.width() << "x"
-            << pic_size.height();
-
-  if (!SetCodedSizeOnInputQueue(pic_size)) {
-    VLOGF(1) << "Failed to set coded size on input queue";
-    return false;
-  }
-
-  auto frame_layout = SetupOutputFormat(pic_size, avd_->GetVisibleRect());
-  if (!frame_layout) {
-    VLOGF(1) << "No format is available with thew new resolution";
-    return false;
-  }
-
-  auto coded_size = frame_layout->coded_size();
-  DCHECK_EQ(coded_size.width() % 16, 0);
-  DCHECK_EQ(coded_size.height() % 16, 0);
-  if (!gfx::Rect(coded_size).Contains(gfx::Rect(pic_size))) {
-    VLOGF(1) << "Got invalid adjusted coded size: " << coded_size.ToString();
-    return false;
-  }
-
-  // Allocate new output buffers.
-  if (!output_queue_->DeallocateBuffers())
-    return false;
-  size_t num_output_frames = avd_->GetRequiredNumOfPictures();
-  DCHECK_GT(num_output_frames, 0u);
-  if (output_queue_->AllocateBuffers(num_output_frames, V4L2_MEMORY_DMABUF) ==
-      0) {
-    VLOGF(1) << "Failed to request output buffers.";
-    return false;
-  }
-  if (output_queue_->AllocatedBuffersCount() != num_output_frames) {
-    VLOGF(1) << "Could not allocate requested number of output buffers.";
-    return false;
-  }
-  frame_pool_->SetMaxNumFrames(num_output_frames);
-
-  if (!StartStreamV4L2Queue())
-    return false;
-
-  SetState(State::kDecoding);
-  return true;
-}
-
-scoped_refptr<V4L2DecodeSurface> V4L2SliceVideoDecoder::CreateSurface() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DVLOGF(4);
-
-  // Request VideoFrame.
-  scoped_refptr<VideoFrame> frame = frame_pool_->GetFrame();
-  if (!frame) {
-    // We allocate the same number of output buffer slot in V4L2 device and the
-    // output VideoFrame. If there is free output buffer slot but no free
-    // VideoFrame, surface_it means the VideoFrame is not released at client
-    // side. Post PumpDecodeTask when the pool has available frames.
-    DVLOGF(3) << "There is no available VideoFrame.";
-    frame_pool_->NotifyWhenFrameAvailable(base::BindOnce(
-        base::IgnoreResult(&base::SequencedTaskRunner::PostTask),
-        decoder_task_runner_, FROM_HERE,
-        base::BindOnce(&V4L2SliceVideoDecoder::PumpDecodeTask, weak_this_)));
-    return nullptr;
-  }
-
-  // Request V4L2 input and output buffers.
-  V4L2WritableBufferRef input_buf = input_queue_->GetFreeBuffer();
-  V4L2WritableBufferRef output_buf = output_queue_->GetFreeBuffer();
-  if (!input_buf.IsValid() || !output_buf.IsValid()) {
-    DVLOGF(3) << "There is no free V4L2 buffer.";
-    return nullptr;
-  }
-
-  scoped_refptr<V4L2DecodeSurface> dec_surface;
-  if (supports_requests_) {
-    DCHECK(!requests_.empty());
-    base::ScopedFD request = std::move(requests_.front());
-    requests_.pop();
-    auto ret = V4L2RequestDecodeSurface::Create(
-        std::move(input_buf), std::move(output_buf), std::move(frame),
-        request.get());
-    requests_.push(std::move(request));
-    if (!ret) {
-      DVLOGF(3) << "Could not create surface.";
-      return nullptr;
-    }
-    dec_surface = std::move(*ret);
-  } else {
-    dec_surface = new V4L2ConfigStoreDecodeSurface(
-        std::move(input_buf), std::move(output_buf), std::move(frame));
-  }
-
-  return dec_surface;
-}
-
-void V4L2SliceVideoDecoder::ReuseOutputBuffer(V4L2ReadableBufferRef buffer) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DVLOGF(3) << "Reuse output surface #" << buffer->BufferId();
-
-  // Resume decoding in case of ran out of surface.
-  if (pause_reason_ == PauseReason::kRanOutOfSurfaces) {
-    decoder_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&V4L2SliceVideoDecoder::PumpDecodeTask, weak_this_));
-  }
-}
-
-bool V4L2SliceVideoDecoder::SubmitSlice(
-    const scoped_refptr<V4L2DecodeSurface>& dec_surface,
-    const uint8_t* data,
-    size_t size) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DVLOGF(3);
-
-  size_t plane_size = dec_surface->input_buffer().GetPlaneSize(0);
-  size_t bytes_used = dec_surface->input_buffer().GetPlaneBytesUsed(0);
-  if (size > plane_size - bytes_used) {
-    VLOGF(1) << "The size of submitted slice(" << size
-             << ") is larger than the remaining buffer size("
-             << plane_size - bytes_used << "). Plane size is " << plane_size;
-    SetState(State::kError);
-    return false;
-  }
-
-  void* mapping = dec_surface->input_buffer().GetPlaneMapping(0);
-  memcpy(reinterpret_cast<uint8_t*>(mapping) + bytes_used, data, size);
-  dec_surface->input_buffer().SetPlaneBytesUsed(0, bytes_used + size);
-  return true;
-}
-
-void V4L2SliceVideoDecoder::DecodeSurface(
-    const scoped_refptr<V4L2DecodeSurface>& dec_surface) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DVLOGF(3);
-
-  // Enqueue input_buf and output_buf
-  dec_surface->input_buffer().PrepareQueueBuffer(*dec_surface);
-  if (!std::move(dec_surface->input_buffer()).QueueMMap()) {
-    SetState(State::kError);
-    return;
-  }
-
-  if (!std::move(dec_surface->output_buffer())
-           .QueueDMABuf(dec_surface->video_frame()->DmabufFds())) {
-    SetState(State::kError);
-    return;
-  }
-
-  if (!dec_surface->Submit()) {
-    VLOGF(1) << "Error while submitting frame for decoding!";
-    SetState(State::kError);
-    return;
-  }
-
-  surfaces_at_device_.push(std::move(dec_surface));
-}
-
-void V4L2SliceVideoDecoder::SurfaceReady(
-    const scoped_refptr<V4L2DecodeSurface>& dec_surface,
-    int32_t bitstream_id,
-    const gfx::Rect& visible_rect,
-    const VideoColorSpace& /* color_space */) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DVLOGF(3);
-
-  // Find the timestamp associated with |bitstream_id|. It's possible that a
-  // surface is output multiple times for different |bitstream_id|s (e.g. VP9
-  // show_existing_frame feature). This means we need to output the same frame
-  // again with a different timestamp.
-  // On some rare occasions it's also possible that a single DecoderBuffer
-  // produces multiple surfaces with the same |bitstream_id|, so we shouldn't
-  // remove the timestamp from the cache.
-  const auto it = bitstream_id_to_timestamp_.Peek(bitstream_id);
-  DCHECK(it != bitstream_id_to_timestamp_.end());
-  base::TimeDelta timestamp = it->second;
-
-  dec_surface->SetVisibleRect(visible_rect);
-  output_request_queue_.push(
-      OutputRequest::Surface(std::move(dec_surface), timestamp));
-  PumpOutputSurfaces();
+  backend_->EnqueueDecodeTask(std::move(buffer), std::move(decode_cb),
+                              bitstream_id);
 }
 
 bool V4L2SliceVideoDecoder::StartStreamV4L2Queue() {
@@ -1054,8 +513,81 @@
   if (output_queue_)
     output_queue_->Streamoff();
 
-  while (!surfaces_at_device_.empty())
-    surfaces_at_device_.pop();
+  backend_->OnStreamStopped();
+
+  return true;
+}
+
+void V4L2SliceVideoDecoder::InitiateFlush() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
+  DVLOGF(3);
+
+  SetState(State::kFlushing);
+}
+
+void V4L2SliceVideoDecoder::CompleteFlush() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
+  DVLOGF(3);
+
+  SetState(State::kDecoding);
+}
+
+bool V4L2SliceVideoDecoder::ChangeResolution(gfx::Size pic_size,
+                                             gfx::Rect visible_rect,
+                                             size_t num_output_frames) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
+  DVLOGF(3);
+  DCHECK_EQ(state_, State::kFlushing);
+  DCHECK_EQ(input_queue_->QueuedBuffersCount(), 0u);
+  DCHECK_EQ(output_queue_->QueuedBuffersCount(), 0u);
+
+  if (!StopStreamV4L2Queue())
+    return false;
+
+  if (!SetCodedSizeOnInputQueue(pic_size)) {
+    VLOGF(1) << "Failed to set coded size on input queue";
+    return false;
+  }
+
+  auto frame_layout = SetupOutputFormat(pic_size, visible_rect);
+  if (!frame_layout) {
+    VLOGF(1) << "No format is available with thew new resolution";
+    SetState(State::kError);
+    return false;
+  }
+
+  auto coded_size = frame_layout->coded_size();
+  DCHECK_EQ(coded_size.width() % 16, 0);
+  DCHECK_EQ(coded_size.height() % 16, 0);
+  if (!gfx::Rect(coded_size).Contains(gfx::Rect(pic_size))) {
+    VLOGF(1) << "Got invalid adjusted coded size: " << coded_size.ToString();
+    SetState(State::kError);
+    return false;
+  }
+
+  // Allocate new output buffers.
+  if (!output_queue_->DeallocateBuffers()) {
+    SetState(State::kError);
+    return false;
+  }
+  DCHECK_GT(num_output_frames, 0u);
+  if (output_queue_->AllocateBuffers(num_output_frames, V4L2_MEMORY_DMABUF) ==
+      0) {
+    VLOGF(1) << "Failed to request output buffers.";
+    SetState(State::kError);
+    return false;
+  }
+  if (output_queue_->AllocatedBuffersCount() != num_output_frames) {
+    VLOGF(1) << "Could not allocate requested number of output buffers.";
+    SetState(State::kError);
+    return false;
+  }
+  frame_pool_->SetMaxNumFrames(num_output_frames);
+
+  if (!StartStreamV4L2Queue()) {
+    SetState(State::kError);
+    return false;
+  }
 
   return true;
 }
@@ -1067,7 +599,6 @@
             << ", Number of queued output buffers: "
             << output_queue_->QueuedBuffersCount();
 
-  bool resume_decode = false;
   // Dequeue V4L2 output buffer first to reduce output latency.
   bool success;
   V4L2ReadableBufferRef dequeued_buffer;
@@ -1080,29 +611,7 @@
     if (!dequeued_buffer)
       break;
 
-    // Mark the output buffer decoded, and try to output surface.
-    DCHECK(!surfaces_at_device_.empty());
-    auto surface = std::move(surfaces_at_device_.front());
-    DCHECK_EQ(static_cast<size_t>(surface->output_record()),
-              dequeued_buffer->BufferId());
-    surfaces_at_device_.pop();
-
-    surface->SetDecoded();
-    // VP9Decoder update context after surface is decoded. Resume decoding for
-    // previous pause of AVD::kWaitSubFrameDecoded.
-    resume_decode = true;
-
-    // Keep a reference to the V4L2 buffer until the buffer is reused. The
-    // reason for this is that the config store uses V4L2 buffer IDs to
-    // reference frames, therefore we cannot reuse the same V4L2 buffer ID for
-    // another decode operation until all references to that frame are gone.
-    // Request API does not have this limitation, so we can probably remove this
-    // after config store is gone.
-    surface->SetReleaseCallback(
-        base::BindOnce(&V4L2SliceVideoDecoder::ReuseOutputBuffer, weak_this_,
-                       std::move(dequeued_buffer)));
-
-    PumpOutputSurfaces();
+    backend_->OnOutputBufferDequeued(std::move(dequeued_buffer));
   }
 
   // Dequeue V4L2 input buffer.
@@ -1115,12 +624,6 @@
     if (!dequeued_buffer)
       break;
   }
-
-  if (resume_decode && pause_reason_ == PauseReason::kWaitSubFrameDecoded) {
-    decoder_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&V4L2SliceVideoDecoder::PumpDecodeTask, weak_this_));
-  }
 }
 
 void V4L2SliceVideoDecoder::RunDecodeCB(DecodeCB cb, DecodeStatus status) {
@@ -1130,7 +633,7 @@
                                 base::BindOnce(std::move(cb), status));
 }
 
-void V4L2SliceVideoDecoder::RunOutputCB(scoped_refptr<VideoFrame> frame,
+void V4L2SliceVideoDecoder::OutputFrame(scoped_refptr<VideoFrame> frame,
                                         const gfx::Rect& visible_rect,
                                         base::TimeDelta timestamp) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
@@ -1199,11 +702,25 @@
 
   if (new_state == State::kError) {
     VLOGF(1) << "Error occurred.";
-    ClearPendingRequests(DecodeStatus::DECODE_ERROR);
+    backend_->ClearPendingRequests(DecodeStatus::DECODE_ERROR);
     return;
   }
   state_ = new_state;
   return;
 }
 
+void V4L2SliceVideoDecoder::OnBackendError() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
+  DVLOGF(2);
+
+  SetState(State::kError);
+}
+
+bool V4L2SliceVideoDecoder::IsDecoding() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
+  DVLOGF(3);
+
+  return state_ == State::kDecoding;
+}
+
 }  // namespace media
diff --git a/media/gpu/v4l2/v4l2_slice_video_decoder.h b/media/gpu/v4l2/v4l2_slice_video_decoder.h
index ab01959..3ff593bd 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decoder.h
+++ b/media/gpu/v4l2/v4l2_slice_video_decoder.h
@@ -27,18 +27,18 @@
 #include "media/base/video_frame_layout.h"
 #include "media/base/video_types.h"
 #include "media/gpu/media_gpu_export.h"
-#include "media/gpu/v4l2/v4l2_decode_surface_handler.h"
 #include "media/gpu/v4l2/v4l2_device.h"
+#include "media/gpu/v4l2/v4l2_video_decoder_backend.h"
 #include "media/video/supported_video_decoder_config.h"
 
 namespace media {
 
 class AcceleratedVideoDecoder;
 class DmabufVideoFramePool;
-class V4L2DecodeSurface;
 
-class MEDIA_GPU_EXPORT V4L2SliceVideoDecoder : public VideoDecoder,
-                                               public V4L2DecodeSurfaceHandler {
+class MEDIA_GPU_EXPORT V4L2SliceVideoDecoder
+    : public VideoDecoder,
+      public V4L2VideoDecoderBackend::Client {
  public:
   using GetFramePoolCB = base::RepeatingCallback<DmabufVideoFramePool*()>;
 
@@ -68,17 +68,18 @@
   void Reset(base::OnceClosure closure) override;
   void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override;
 
-  // V4L2DecodeSurfaceHandler implementation.
-  scoped_refptr<V4L2DecodeSurface> CreateSurface() override;
-  bool SubmitSlice(const scoped_refptr<V4L2DecodeSurface>& dec_surface,
-                   const uint8_t* data,
-                   size_t size) override;
-  void DecodeSurface(
-      const scoped_refptr<V4L2DecodeSurface>& dec_surface) override;
-  void SurfaceReady(const scoped_refptr<V4L2DecodeSurface>& dec_surface,
-                    int32_t bitstream_id,
-                    const gfx::Rect& visible_rect,
-                    const VideoColorSpace& /* color_space */) override;
+  // V4L2VideoDecoderBackend::Client implementation
+  void OnBackendError() override;
+  bool IsDecoding() const override;
+  void InitiateFlush() override;
+  void CompleteFlush() override;
+  bool ChangeResolution(gfx::Size pic_size,
+                        gfx::Rect visible_rect,
+                        size_t num_output_frames) override;
+  void RunDecodeCB(DecodeCB cb, DecodeStatus status) override;
+  void OutputFrame(scoped_refptr<VideoFrame> frame,
+                   const gfx::Rect& visible_rect,
+                   base::TimeDelta timestamp) override;
 
  private:
   friend class V4L2SliceVideoDecoderTest;
@@ -91,29 +92,6 @@
   ~V4L2SliceVideoDecoder() override;
   void Destroy() override;
 
-  // Request for decoding buffer. Every Decode() call generates 1 DecodeRequest.
-  struct DecodeRequest {
-    // The decode buffer passed from Decode().
-    scoped_refptr<DecoderBuffer> buffer;
-    // The callback function passed from Decode().
-    DecodeCB decode_cb;
-    // The identifier for the decoder buffer.
-    int32_t bitstream_id;
-
-    DecodeRequest(scoped_refptr<DecoderBuffer> buf, DecodeCB cb, int32_t id);
-
-    // Allow move, but not copy
-    DecodeRequest(DecodeRequest&&);
-    DecodeRequest& operator=(DecodeRequest&&);
-
-    ~DecodeRequest();
-
-    DISALLOW_COPY_AND_ASSIGN(DecodeRequest);
-  };
-
-  // Request for displaying the surface or calling the decode callback.
-  struct OutputRequest;
-
   enum class State {
     // Initial state. Transitions to |kDecoding| if Initialize() is successful,
     // |kError| otherwise.
@@ -128,18 +106,6 @@
     kError,
   };
 
-  // The reason the decoding is paused.
-  enum class PauseReason {
-    // Not stopped, decoding normally.
-    kNone,
-    // Cannot create a new V4L2 surface. Waiting for surfaces to be released.
-    kRanOutOfSurfaces,
-    // A VP9 superframe contains multiple subframes. Before decoding the next
-    // subframe, we need to wait for previous subframes decoded and update the
-    // context.
-    kWaitSubFrameDecoded,
-  };
-
   class BitstreamIdGenerator {
    public:
     BitstreamIdGenerator() { DETACH_FROM_SEQUENCE(sequence_checker_); }
@@ -185,30 +151,11 @@
   void DestroyTask();
   // Reset on decoder thread.
   void ResetTask(base::OnceClosure closure);
-  // Reset |avd_|, clear all pending requests, and call all pending decode
-  // callback with |status| argument.
-  void ClearPendingRequests(DecodeStatus status);
 
-  // Enqueue |request| to the pending decode request queue, and try to decode
-  // from the queue.
+  // Enqueue |buffer| to be decoded. |decode_cb| will be called once |buffer|
+  // is no longer used.
   void EnqueueDecodeTask(scoped_refptr<DecoderBuffer> buffer,
                          V4L2SliceVideoDecoder::DecodeCB decode_cb);
-  // Try to decode buffer from the pending decode request queue.
-  // This method stops decoding when:
-  // - Run out of surface
-  // - Flushing or changing resolution
-  // Invoke this method again when these situation ends.
-  void PumpDecodeTask();
-  // Try to output surface from |output_request_queue_|.
-  // This method stops outputting surface when the first surface is not dequeued
-  // from the V4L2 device. Invoke this method again when any surface is
-  // dequeued from the V4L2 device.
-  void PumpOutputSurfaces();
-  // Setup the format of V4L2 output buffer, and allocate new buffer set.
-  bool ChangeResolution();
-  // Callback which is called when V4L2 surface is destroyed.
-  void ReuseOutputBuffer(V4L2ReadableBufferRef buffer);
-
   // Start streaming V4L2 input and output queues. Attempt to start
   // |device_poll_thread_| before starting streaming.
   bool StartStreamV4L2Queue();
@@ -218,27 +165,18 @@
   // Try to dequeue input and output buffers from device.
   void ServiceDeviceTask(bool event);
 
-  // Convert the frame and call the output callback.
-  void RunOutputCB(scoped_refptr<VideoFrame> frame,
-                   const gfx::Rect& visible_rect,
-                   base::TimeDelta timestamp);
-  // Call the decode callback and count the number of pending callbacks.
-  void RunDecodeCB(DecodeCB cb, DecodeStatus status);
   // Change the state and check the state transition is valid.
   void SetState(State new_state);
 
-  // Check whether request api is supported or not.
-  bool CheckRequestAPISupport();
-  // Allocate necessary request buffers is request api is supported.
-  bool AllocateRequests();
+  // The V4L2 backend, i.e. the part of the decoder that sends
+  // decoding jobs to the kernel.
+  std::unique_ptr<V4L2VideoDecoderBackend> backend_;
 
   // V4L2 device in use.
   scoped_refptr<V4L2Device> device_;
   // VideoFrame manager used to allocate and recycle video frame.
   GetFramePoolCB get_pool_cb_;
   DmabufVideoFramePool* frame_pool_ = nullptr;
-  // Video decoder used to parse stream headers by software.
-  std::unique_ptr<AcceleratedVideoDecoder> avd_;
 
   // Client task runner. All public methods of VideoDecoder interface are
   // executed at this task runner.
@@ -249,8 +187,6 @@
 
   // State of the instance.
   State state_ = State::kUninitialized;
-  // Indicates why decoding is currently paused.
-  PauseReason pause_reason_ = PauseReason::kNone;
 
   // Parameters for generating output VideoFrame.
   base::Optional<VideoFrameLayout> frame_layout_;
@@ -259,41 +195,16 @@
 
   // Callbacks passed from Initialize().
   OutputCB output_cb_;
-  // Callbacks of EOS buffer passed from Decode().
-  DecodeCB flush_cb_;
 
   // V4L2 input and output queue.
   scoped_refptr<V4L2Queue> input_queue_;
   scoped_refptr<V4L2Queue> output_queue_;
 
-  // The time at which each buffer decode operation started. Not each decode
-  // operation leads to a frame being output and frames might be reordered, so
-  // we don't know when it's safe to drop a timestamp. This means we need to use
-  // a cache here, with a size large enough to account for frame reordering.
-  base::MRUCache<int32_t, base::TimeDelta> bitstream_id_to_timestamp_;
-
-  // Queue of pending decode request.
-  base::queue<DecodeRequest> decode_request_queue_;
-  // Surfaces enqueued to V4L2 device. Since we are stateless, they are
-  // guaranteed to be proceeded in FIFO order.
-  base::queue<scoped_refptr<V4L2DecodeSurface>> surfaces_at_device_;
-  // The decode request which is currently processed.
-  base::Optional<DecodeRequest> current_decode_request_;
-  // Queue of pending output request.
-  base::queue<OutputRequest> output_request_queue_;
+  BitstreamIdGenerator bitstream_id_generator_;
 
   // True if the decoder needs bitstream conversion before decoding.
   bool needs_bitstream_conversion_ = false;
 
-  BitstreamIdGenerator bitstream_id_generator_;
-
-  // Set to true by CreateInputBuffers() if the codec driver supports requests.
-  bool supports_requests_ = false;
-  // FIFO queue of requests, only used if supports_requests_ is true.
-  std::queue<base::ScopedFD> requests_;
-  // Stores the media file descriptor, only used if supports_requests_ is true.
-  base::ScopedFD media_fd_;
-
   SEQUENCE_CHECKER(client_sequence_checker_);
   SEQUENCE_CHECKER(decoder_sequence_checker_);
 
diff --git a/media/gpu/v4l2/v4l2_video_decoder_backend.cc b/media/gpu/v4l2/v4l2_video_decoder_backend.cc
new file mode 100644
index 0000000..a01b317
--- /dev/null
+++ b/media/gpu/v4l2/v4l2_video_decoder_backend.cc
@@ -0,0 +1,28 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/gpu/v4l2/v4l2_video_decoder_backend.h"
+
+#include "base/logging.h"
+#include "media/gpu/macros.h"
+#include "media/gpu/v4l2/v4l2_device.h"
+
+namespace media {
+
+V4L2VideoDecoderBackend::V4L2VideoDecoderBackend(
+    Client* const client,
+    scoped_refptr<V4L2Device> device)
+    : client_(client), device_(std::move(device)) {
+  input_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+  output_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+  if (!input_queue_ || !output_queue_) {
+    VLOGF(1) << "Failed to get V4L2 queue. This should not happen since the "
+             << "queues are supposed to be initialized when we are called.";
+    NOTREACHED();
+  }
+}
+
+V4L2VideoDecoderBackend::~V4L2VideoDecoderBackend() = default;
+
+}  // namespace media
diff --git a/media/gpu/v4l2/v4l2_video_decoder_backend.h b/media/gpu/v4l2/v4l2_video_decoder_backend.h
new file mode 100644
index 0000000..512f3e2
--- /dev/null
+++ b/media/gpu/v4l2/v4l2_video_decoder_backend.h
@@ -0,0 +1,102 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_GPU_V4L2_V4L2_VIDEO_DECODER_BACKEND_H_
+#define MEDIA_GPU_V4L2_V4L2_VIDEO_DECODER_BACKEND_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "media/base/decode_status.h"
+#include "media/base/video_decoder.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace media {
+
+class V4L2Device;
+class V4L2Queue;
+class V4L2ReadableBuffer;
+using V4L2ReadableBufferRef = scoped_refptr<V4L2ReadableBuffer>;
+
+// Abstract class that performs the low-level V4L2 decoding tasks depending
+// on the decoding API chosen (stateful or stateless).
+//
+// The backend receives encoded buffers via EnqueueDecodeTask() and is
+// responsible for acquiring the V4L2 resources (output and capture buffers,
+// etc) and sending them to the V4L2 driver. When a decoded buffer is dequeued,
+// |OutputBufferDequeued| is automatically called from the decoder.
+//
+// The backend can call into some of the decoder methods, notably OutputFrame()
+// to send a |VideoFrame| to the decoder's client, and Error() to signal that
+// an unrecoverable error has occurred.
+//
+// This class must run entirely inside the decoder thread. All overridden
+// methods must check that they are called from sequence_checker_.
+class V4L2VideoDecoderBackend {
+ public:
+  // Interface for the backend to call back into the decoder it is serving.
+  // All methods must be called from the same sequence as the backend.
+  class Client {
+   public:
+    // Inform that an unrecoverable error has occurred in the backend.
+    virtual void OnBackendError() = 0;
+    // Returns true is we are in a state that allows decoding to proceed.
+    virtual bool IsDecoding() const = 0;
+    // Start flushing. No new decoding requests will be processed until
+    // CompleteFlush() is called.
+    virtual void InitiateFlush() = 0;
+    // Inform the flushing is complete.
+    virtual void CompleteFlush() = 0;
+    // Stop the stream to reallocate the CAPTURE buffers. Can only be done
+    // between calls to |InitiateFlush| and |CompleteFlush|.
+    virtual bool ChangeResolution(gfx::Size pic_size,
+                                  gfx::Rect visible_rect,
+                                  size_t num_output_frames) = 0;
+    // Call the decode callback and count the number of pending callbacks.
+    virtual void RunDecodeCB(VideoDecoder::DecodeCB cb,
+                             DecodeStatus status) = 0;
+    // Convert the frame and call the output callback.
+    virtual void OutputFrame(scoped_refptr<VideoFrame> frame,
+                             const gfx::Rect& visible_rect,
+                             base::TimeDelta timestamp) = 0;
+  };
+
+  virtual ~V4L2VideoDecoderBackend();
+
+  virtual bool Initialize() = 0;
+
+  // Schedule |buffer| to be processed, with bitstream ID |bitstream_id|.
+  // The backend must call V4L2SliceVideoDecoder::RunDecodeCB() with |decode_cb|
+  // as argument once the buffer is not used anymore.
+  virtual void EnqueueDecodeTask(scoped_refptr<DecoderBuffer> buffer,
+                                 VideoDecoder::DecodeCB decode_cb,
+                                 int32_t bitstream_id) = 0;
+  // Called by the decoder when it has dequeued a buffer from the CAPTURE queue.
+  virtual void OnOutputBufferDequeued(V4L2ReadableBufferRef buf) = 0;
+  // Called whenever the V4L2 stream is stopped (|Streamoff| called on both
+  // |V4L2Queue|s).
+  virtual void OnStreamStopped() = 0;
+  // Clear all pending decoding tasks and call all pending decode callbacks
+  // with |status| as argument.
+  virtual void ClearPendingRequests(DecodeStatus status) = 0;
+
+ protected:
+  V4L2VideoDecoderBackend(Client* const client,
+                          scoped_refptr<V4L2Device> device);
+
+  // The decoder we are serving. |client_| is the owner of this backend
+  // instance, and is guaranteed to live longer than it. Thus it is safe to use
+  // a raw pointer here.
+  Client* const client_;
+  // V4L2 device to use.
+  scoped_refptr<V4L2Device> device_;
+  // Input and output queued from which to get buffers.
+  scoped_refptr<V4L2Queue> input_queue_;
+  scoped_refptr<V4L2Queue> output_queue_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+  DISALLOW_COPY_AND_ASSIGN(V4L2VideoDecoderBackend);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_GPU_V4L2_V4L2_VIDEO_DECODER_BACKEND_H_
diff --git a/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc b/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc
new file mode 100644
index 0000000..143f773
--- /dev/null
+++ b/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc
@@ -0,0 +1,613 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h"
+
+#include <fcntl.h>
+#include <linux/media.h>
+#include <sys/ioctl.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/sequenced_task_runner.h"
+#include "media/base/decode_status.h"
+#include "media/base/video_codecs.h"
+#include "media/base/video_frame.h"
+#include "media/gpu/accelerated_video_decoder.h"
+#include "media/gpu/macros.h"
+#include "media/gpu/v4l2/v4l2_device.h"
+#include "media/gpu/v4l2/v4l2_h264_accelerator.h"
+#include "media/gpu/v4l2/v4l2_h264_accelerator_legacy.h"
+#include "media/gpu/v4l2/v4l2_vp8_accelerator.h"
+#include "media/gpu/v4l2/v4l2_vp8_accelerator_legacy.h"
+#include "media/gpu/v4l2/v4l2_vp9_accelerator.h"
+
+namespace media {
+
+namespace {
+
+// Size of the timestamp cache, needs to be large enough for frame-reordering.
+constexpr size_t kTimestampCacheSize = 128;
+// Number of requests to allocate for submitting input buffers, if requests
+// are used.
+constexpr size_t kNumRequests = 16;
+
+}  // namespace
+
+struct V4L2StatelessVideoDecoderBackend::OutputRequest {
+  static OutputRequest Surface(scoped_refptr<V4L2DecodeSurface> s,
+                               base::TimeDelta t) {
+    return OutputRequest(std::move(s), t);
+  }
+
+  static OutputRequest FlushFence() { return OutputRequest(kFlushFence); }
+
+  static OutputRequest ChangeResolutionFence() {
+    return OutputRequest(kChangeResolutionFence);
+  }
+
+  bool IsReady() const {
+    return (type != OutputRequestType::kSurface) || surface->decoded();
+  }
+
+  // Allow move, but not copy.
+  OutputRequest(OutputRequest&&) = default;
+
+  enum OutputRequestType {
+    // The surface to be outputted.
+    kSurface,
+    // The fence to indicate the flush request.
+    kFlushFence,
+    // The fence to indicate resolution change request.
+    kChangeResolutionFence,
+  };
+
+  // The type of the request.
+  const OutputRequestType type;
+  // The surface to be outputted.
+  scoped_refptr<V4L2DecodeSurface> surface;
+  // The timestamp of the output frame. Because a surface might be outputted
+  // multiple times with different timestamp, we need to store timestamp out of
+  // surface.
+  base::TimeDelta timestamp;
+
+ private:
+  OutputRequest(scoped_refptr<V4L2DecodeSurface> s, base::TimeDelta t)
+      : type(kSurface), surface(std::move(s)), timestamp(t) {}
+  explicit OutputRequest(OutputRequestType t) : type(t) {}
+
+  DISALLOW_COPY_AND_ASSIGN(OutputRequest);
+};
+
+V4L2StatelessVideoDecoderBackend::DecodeRequest::DecodeRequest(
+    scoped_refptr<DecoderBuffer> buf,
+    VideoDecoder::DecodeCB cb,
+    int32_t id)
+    : buffer(std::move(buf)), decode_cb(std::move(cb)), bitstream_id(id) {}
+
+V4L2StatelessVideoDecoderBackend::DecodeRequest::DecodeRequest(
+    DecodeRequest&&) = default;
+V4L2StatelessVideoDecoderBackend::DecodeRequest&
+V4L2StatelessVideoDecoderBackend::DecodeRequest::operator=(DecodeRequest&&) =
+    default;
+
+V4L2StatelessVideoDecoderBackend::DecodeRequest::~DecodeRequest() = default;
+
+V4L2StatelessVideoDecoderBackend::V4L2StatelessVideoDecoderBackend(
+    Client* const client,
+    scoped_refptr<V4L2Device> device,
+    DmabufVideoFramePool* const frame_pool,
+    VideoCodecProfile profile,
+    scoped_refptr<base::SequencedTaskRunner> task_runner)
+    : V4L2VideoDecoderBackend(client, std::move(device)),
+      frame_pool_(frame_pool),
+      profile_(profile),
+      bitstream_id_to_timestamp_(kTimestampCacheSize),
+      task_runner_(task_runner) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  weak_this_ = weak_this_factory_.GetWeakPtr();
+}
+
+V4L2StatelessVideoDecoderBackend::~V4L2StatelessVideoDecoderBackend() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(surfaces_at_device_.empty());
+
+  if (!output_request_queue_.empty() || flush_cb_ || current_decode_request_ ||
+      !decode_request_queue_.empty()) {
+    VLOGF(1) << "Should not destroy backend during pending decode!";
+  }
+
+  if (avd_) {
+    avd_->Reset();
+    avd_ = nullptr;
+  }
+
+  if (supports_requests_) {
+    requests_ = {};
+    media_fd_.reset();
+  }
+}
+
+bool V4L2StatelessVideoDecoderBackend::Initialize() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!CheckRequestAPISupport()) {
+    VPLOGF(1) << "Failed to check request api support.";
+    return false;
+  }
+
+  // Create codec-specific AcceleratedVideoDecoder.
+  // TODO(akahuang): Check the profile is supported.
+  if (profile_ >= H264PROFILE_MIN && profile_ <= H264PROFILE_MAX) {
+    if (supports_requests_) {
+      avd_.reset(new H264Decoder(
+          std::make_unique<V4L2H264Accelerator>(this, device_.get())));
+    } else {
+      avd_.reset(new H264Decoder(
+          std::make_unique<V4L2LegacyH264Accelerator>(this, device_.get())));
+    }
+  } else if (profile_ >= VP8PROFILE_MIN && profile_ <= VP8PROFILE_MAX) {
+    if (supports_requests_) {
+      avd_.reset(new VP8Decoder(
+          std::make_unique<V4L2VP8Accelerator>(this, device_.get())));
+    } else {
+      avd_.reset(new VP8Decoder(
+          std::make_unique<V4L2LegacyVP8Accelerator>(this, device_.get())));
+    }
+  } else if (profile_ >= VP9PROFILE_MIN && profile_ <= VP9PROFILE_MAX) {
+    avd_.reset(new VP9Decoder(
+        std::make_unique<V4L2VP9Accelerator>(this, device_.get())));
+  } else {
+    VLOGF(1) << "Unsupported profile " << GetProfileName(profile_);
+    return false;
+  }
+
+  if (supports_requests_ && !AllocateRequests()) {
+    return false;
+  }
+
+  return true;
+}
+
+void V4L2StatelessVideoDecoderBackend::ReuseOutputBuffer(
+    V4L2ReadableBufferRef buffer) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DVLOGF(3) << "Reuse output surface #" << buffer->BufferId();
+
+  // Resume decoding in case of ran out of surface.
+  if (pause_reason_ == PauseReason::kRanOutOfSurfaces) {
+    pause_reason_ = PauseReason::kNone;
+    task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&V4L2StatelessVideoDecoderBackend::DoDecodeWork,
+                       weak_this_));
+  }
+}
+
+void V4L2StatelessVideoDecoderBackend::OnOutputBufferDequeued(
+    V4L2ReadableBufferRef dequeued_buffer) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // Mark the output buffer decoded, and try to output surface.
+  DCHECK(!surfaces_at_device_.empty());
+  auto surface = std::move(surfaces_at_device_.front());
+  DCHECK_EQ(static_cast<size_t>(surface->output_record()),
+            dequeued_buffer->BufferId());
+  surfaces_at_device_.pop();
+
+  surface->SetDecoded();
+
+  // Keep a reference to the V4L2 buffer until the buffer is reused. The
+  // reason for this is that the config store uses V4L2 buffer IDs to
+  // reference frames, therefore we cannot reuse the same V4L2 buffer ID for
+  // another decode operation until all references to that frame are gone.
+  // Request API does not have this limitation, so we can probably remove this
+  // after config store is gone.
+  surface->SetReleaseCallback(
+      base::BindOnce(&V4L2StatelessVideoDecoderBackend::ReuseOutputBuffer,
+                     weak_this_, std::move(dequeued_buffer)));
+
+  PumpOutputSurfaces();
+
+  // If we were waiting for an output buffer to be available, schedule a
+  // decode task.
+  if (pause_reason_ == PauseReason::kWaitSubFrameDecoded) {
+    pause_reason_ = PauseReason::kNone;
+    task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&V4L2StatelessVideoDecoderBackend::DoDecodeWork,
+                       weak_this_));
+  }
+}
+
+scoped_refptr<V4L2DecodeSurface>
+V4L2StatelessVideoDecoderBackend::CreateSurface() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DVLOGF(4);
+
+  // Request VideoFrame.
+  scoped_refptr<VideoFrame> frame = frame_pool_->GetFrame();
+  if (!frame) {
+    // We allocate the same number of output buffer slot in V4L2 device and the
+    // output VideoFrame. If there is free output buffer slot but no free
+    // VideoFrame, surface_it means the VideoFrame is not released at client
+    // side. Post DoDecodeWork when the pool has available frames.
+    DVLOGF(3) << "There is no available VideoFrame.";
+    frame_pool_->NotifyWhenFrameAvailable(base::BindOnce(
+        base::IgnoreResult(&base::SequencedTaskRunner::PostTask), task_runner_,
+        FROM_HERE,
+        base::BindOnce(&V4L2StatelessVideoDecoderBackend::DoDecodeWork,
+                       weak_this_)));
+    return nullptr;
+  }
+
+  // Request V4L2 input and output buffers.
+  V4L2WritableBufferRef input_buf = input_queue_->GetFreeBuffer();
+  V4L2WritableBufferRef output_buf = output_queue_->GetFreeBuffer();
+  if (!input_buf.IsValid() || !output_buf.IsValid()) {
+    DVLOGF(3) << "There is no free V4L2 buffer.";
+    return nullptr;
+  }
+
+  scoped_refptr<V4L2DecodeSurface> dec_surface;
+  if (supports_requests_) {
+    DCHECK(!requests_.empty());
+    base::ScopedFD request = std::move(requests_.front());
+    requests_.pop();
+    auto ret = V4L2RequestDecodeSurface::Create(
+        std::move(input_buf), std::move(output_buf), std::move(frame),
+        request.get());
+    requests_.push(std::move(request));
+    if (!ret) {
+      DVLOGF(3) << "Could not create surface.";
+      return nullptr;
+    }
+    dec_surface = std::move(*ret);
+  } else {
+    dec_surface = new V4L2ConfigStoreDecodeSurface(
+        std::move(input_buf), std::move(output_buf), std::move(frame));
+  }
+
+  return dec_surface;
+}
+
+bool V4L2StatelessVideoDecoderBackend::SubmitSlice(
+    const scoped_refptr<V4L2DecodeSurface>& dec_surface,
+    const uint8_t* data,
+    size_t size) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DVLOGF(3);
+
+  size_t plane_size = dec_surface->input_buffer().GetPlaneSize(0);
+  size_t bytes_used = dec_surface->input_buffer().GetPlaneBytesUsed(0);
+  if (size > plane_size - bytes_used) {
+    VLOGF(1) << "The size of submitted slice(" << size
+             << ") is larger than the remaining buffer size("
+             << plane_size - bytes_used << "). Plane size is " << plane_size;
+    client_->OnBackendError();
+    return false;
+  }
+
+  void* mapping = dec_surface->input_buffer().GetPlaneMapping(0);
+  memcpy(reinterpret_cast<uint8_t*>(mapping) + bytes_used, data, size);
+  dec_surface->input_buffer().SetPlaneBytesUsed(0, bytes_used + size);
+  return true;
+}
+
+void V4L2StatelessVideoDecoderBackend::DecodeSurface(
+    const scoped_refptr<V4L2DecodeSurface>& dec_surface) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DVLOGF(3);
+
+  // Enqueue input_buf and output_buf
+  dec_surface->input_buffer().PrepareQueueBuffer(*dec_surface);
+
+  if (!std::move(dec_surface->input_buffer()).QueueMMap()) {
+    client_->OnBackendError();
+    return;
+  }
+
+  if (!std::move(dec_surface->output_buffer())
+           .QueueDMABuf(dec_surface->video_frame()->DmabufFds())) {
+    client_->OnBackendError();
+    return;
+  }
+
+  if (!dec_surface->Submit()) {
+    VLOGF(1) << "Error while submitting frame for decoding!";
+    client_->OnBackendError();
+    return;
+  }
+
+  surfaces_at_device_.push(std::move(dec_surface));
+}
+
+void V4L2StatelessVideoDecoderBackend::SurfaceReady(
+    const scoped_refptr<V4L2DecodeSurface>& dec_surface,
+    int32_t bitstream_id,
+    const gfx::Rect& visible_rect,
+    const VideoColorSpace& /* color_space */) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DVLOGF(3);
+
+  // Find the timestamp associated with |bitstream_id|. It's possible that a
+  // surface is output multiple times for different |bitstream_id|s (e.g. VP9
+  // show_existing_frame feature). This means we need to output the same frame
+  // again with a different timestamp.
+  // On some rare occasions it's also possible that a single DecoderBuffer
+  // produces multiple surfaces with the same |bitstream_id|, so we shouldn't
+  // remove the timestamp from the cache.
+  const auto it = bitstream_id_to_timestamp_.Peek(bitstream_id);
+  DCHECK(it != bitstream_id_to_timestamp_.end());
+  base::TimeDelta timestamp = it->second;
+
+  dec_surface->SetVisibleRect(visible_rect);
+  output_request_queue_.push(
+      OutputRequest::Surface(std::move(dec_surface), timestamp));
+  PumpOutputSurfaces();
+}
+
+void V4L2StatelessVideoDecoderBackend::EnqueueDecodeTask(
+    scoped_refptr<DecoderBuffer> buffer,
+    VideoDecoder::DecodeCB decode_cb,
+    int32_t bitstream_id) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!buffer->end_of_stream()) {
+    bitstream_id_to_timestamp_.Put(bitstream_id, buffer->timestamp());
+  }
+
+  decode_request_queue_.push(
+      DecodeRequest(std::move(buffer), std::move(decode_cb), bitstream_id));
+
+  // If we are already decoding, then we don't need to pump again.
+  if (!current_decode_request_)
+    DoDecodeWork();
+}
+
+void V4L2StatelessVideoDecoderBackend::DoDecodeWork() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!client_->IsDecoding())
+    return;
+
+  if (!PumpDecodeTask())
+    client_->OnBackendError();
+}
+
+bool V4L2StatelessVideoDecoderBackend::PumpDecodeTask() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DVLOGF(3) << " Number of Decode requests: " << decode_request_queue_.size();
+
+  pause_reason_ = PauseReason::kNone;
+  while (true) {
+    switch (avd_->Decode()) {
+      case AcceleratedVideoDecoder::kAllocateNewSurfaces:
+        DVLOGF(3) << "Need to change resolution. Pause decoding.";
+        client_->InitiateFlush();
+
+        output_request_queue_.push(OutputRequest::ChangeResolutionFence());
+        PumpOutputSurfaces();
+        return true;
+
+      case AcceleratedVideoDecoder::kRanOutOfStreamData:
+        // Current decode request is finished processing.
+        if (current_decode_request_) {
+          DCHECK(current_decode_request_->decode_cb);
+          client_->RunDecodeCB(std::move(current_decode_request_->decode_cb),
+                               DecodeStatus::OK);
+          current_decode_request_ = base::nullopt;
+        }
+
+        // Process next decode request.
+        if (decode_request_queue_.empty())
+          return true;
+        current_decode_request_ = std::move(decode_request_queue_.front());
+        decode_request_queue_.pop();
+
+        if (current_decode_request_->buffer->end_of_stream()) {
+          if (!avd_->Flush()) {
+            VLOGF(1) << "Failed flushing the decoder.";
+            return false;
+          }
+          // Put the decoder in an idle state, ready to resume.
+          avd_->Reset();
+
+          client_->InitiateFlush();
+          DCHECK(!flush_cb_);
+          flush_cb_ = std::move(current_decode_request_->decode_cb);
+
+          output_request_queue_.push(OutputRequest::FlushFence());
+          PumpOutputSurfaces();
+          current_decode_request_ = base::nullopt;
+          return true;
+        }
+
+        avd_->SetStream(current_decode_request_->bitstream_id,
+                        *current_decode_request_->buffer);
+        break;
+
+      case AcceleratedVideoDecoder::kRanOutOfSurfaces:
+        DVLOGF(3) << "Ran out of surfaces. Resume when buffer is returned.";
+        pause_reason_ = PauseReason::kRanOutOfSurfaces;
+        return true;
+
+      case AcceleratedVideoDecoder::kNeedContextUpdate:
+        DVLOGF(3) << "Awaiting context update";
+        pause_reason_ = PauseReason::kWaitSubFrameDecoded;
+        return true;
+
+      case AcceleratedVideoDecoder::kDecodeError:
+        DVLOGF(3) << "Error decoding stream";
+        return false;
+
+      case AcceleratedVideoDecoder::kTryAgain:
+        NOTREACHED() << "Should not reach here unless this class accepts "
+                        "encrypted streams.";
+        DVLOGF(4) << "No key for decoding stream.";
+        return false;
+    }
+  }
+}
+
+void V4L2StatelessVideoDecoderBackend::PumpOutputSurfaces() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DVLOGF(3) << "Number of display surfaces: " << output_request_queue_.size();
+
+  bool resume_decode = false;
+  while (!output_request_queue_.empty()) {
+    if (!output_request_queue_.front().IsReady()) {
+      DVLOGF(3) << "The first surface is not ready yet.";
+      break;
+    }
+
+    OutputRequest request = std::move(output_request_queue_.front());
+    output_request_queue_.pop();
+    switch (request.type) {
+      case OutputRequest::kFlushFence:
+        DCHECK(output_request_queue_.empty());
+        DVLOGF(2) << "Flush finished.";
+        client_->RunDecodeCB(std::move(flush_cb_), DecodeStatus::OK);
+        resume_decode = true;
+        break;
+
+      case OutputRequest::kChangeResolutionFence:
+        DCHECK(output_request_queue_.empty());
+        if (!ChangeResolution()) {
+          client_->OnBackendError();
+          return;
+        }
+        resume_decode = true;
+        break;
+
+      case OutputRequest::kSurface:
+        scoped_refptr<V4L2DecodeSurface> surface = std::move(request.surface);
+
+        DCHECK(surface->video_frame());
+        client_->OutputFrame(surface->video_frame(), surface->visible_rect(),
+                             request.timestamp);
+        break;
+    }
+  }
+
+  if (resume_decode) {
+    client_->CompleteFlush();
+    task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&V4L2StatelessVideoDecoderBackend::DoDecodeWork,
+                       weak_this_));
+  }
+}
+
+bool V4L2StatelessVideoDecoderBackend::ChangeResolution() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // We change resolution after outputting all pending surfaces, there should
+  // be no V4L2DecodeSurface left.
+  DCHECK(surfaces_at_device_.empty());
+  DCHECK(output_request_queue_.empty());
+  // Set output format with the new resolution.
+  gfx::Size pic_size = avd_->GetPicSize();
+  DCHECK(!pic_size.IsEmpty());
+  DVLOGF(3) << "Change resolution to " << pic_size.ToString();
+
+  size_t num_output_frames = avd_->GetRequiredNumOfPictures();
+  gfx::Rect visible_rect = avd_->GetVisibleRect();
+  return client_->ChangeResolution(pic_size, visible_rect, num_output_frames);
+}
+
+void V4L2StatelessVideoDecoderBackend::OnStreamStopped() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DVLOGF(3);
+
+  // The V4L2 stream has been stopped stopped, so all surfaces on the device
+  // have been returned to the client.
+  surfaces_at_device_ = {};
+}
+
+void V4L2StatelessVideoDecoderBackend::ClearPendingRequests(
+    DecodeStatus status) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DVLOGF(3);
+
+  if (avd_)
+    avd_->Reset();
+
+  // Clear output_request_queue_.
+  while (!output_request_queue_.empty())
+    output_request_queue_.pop();
+
+  if (flush_cb_)
+    client_->RunDecodeCB(std::move(flush_cb_), status);
+
+  // Clear current_decode_request_ and decode_request_queue_.
+  if (current_decode_request_) {
+    client_->RunDecodeCB(std::move(current_decode_request_->decode_cb), status);
+    current_decode_request_ = base::nullopt;
+  }
+
+  while (!decode_request_queue_.empty()) {
+    auto request = std::move(decode_request_queue_.front());
+    decode_request_queue_.pop();
+    client_->RunDecodeCB(std::move(request.decode_cb), status);
+  }
+}
+
+bool V4L2StatelessVideoDecoderBackend::CheckRequestAPISupport() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DVLOGF(3);
+
+  struct v4l2_requestbuffers reqbufs;
+  memset(&reqbufs, 0, sizeof(reqbufs));
+  reqbufs.count = 0;
+  reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+  reqbufs.memory = V4L2_MEMORY_MMAP;
+  if (device_->Ioctl(VIDIOC_REQBUFS, &reqbufs) != 0) {
+    VPLOGF(1) << "VIDIOC_REQBUFS ioctl failed.";
+    return false;
+  }
+  if (reqbufs.capabilities & V4L2_BUF_CAP_SUPPORTS_REQUESTS) {
+    supports_requests_ = true;
+    VLOGF(1) << "Using request API.";
+    DCHECK(!media_fd_.is_valid());
+    // Let's try to open the media device
+    // TODO(crbug.com/985230): remove this hardcoding, replace with V4L2Device
+    // integration.
+    int media_fd = open("/dev/media-dec0", O_RDWR, 0);
+    if (media_fd < 0) {
+      VPLOGF(1) << "Failed to open media device.";
+      return false;
+    }
+    media_fd_ = base::ScopedFD(media_fd);
+  } else {
+    VLOGF(1) << "Using config store.";
+  }
+
+  return true;
+}
+
+bool V4L2StatelessVideoDecoderBackend::AllocateRequests() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DVLOGF(3);
+
+  DCHECK(requests_.empty());
+
+  for (size_t i = 0; i < kNumRequests; i++) {
+    int request_fd;
+
+    int ret = HANDLE_EINTR(
+        ioctl(media_fd_.get(), MEDIA_IOC_REQUEST_ALLOC, &request_fd));
+    if (ret < 0) {
+      VPLOGF(1) << "Failed to create request: ";
+      return false;
+    }
+
+    requests_.push(base::ScopedFD(request_fd));
+  }
+  DCHECK_EQ(requests_.size(), kNumRequests);
+
+  return true;
+}
+
+}  // namespace media
diff --git a/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h b/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h
new file mode 100644
index 0000000..b5d9d7c
--- /dev/null
+++ b/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h
@@ -0,0 +1,177 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_GPU_V4L2_V4L2_VIDEO_DECODER_BACKEND_STATELESS_H_
+#define MEDIA_GPU_V4L2_V4L2_VIDEO_DECODER_BACKEND_STATELESS_H_
+
+#include "base/containers/mru_cache.h"
+#include "base/containers/queue.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/sequenced_task_runner.h"
+#include "media/base/decode_status.h"
+#include "media/base/video_decoder.h"
+#include "media/gpu/linux/dmabuf_video_frame_pool.h"
+#include "media/gpu/v4l2/v4l2_decode_surface_handler.h"
+#include "media/gpu/v4l2/v4l2_video_decoder_backend.h"
+
+namespace media {
+
+class AcceleratedVideoDecoder;
+
+class V4L2StatelessVideoDecoderBackend : public V4L2VideoDecoderBackend,
+                                         public V4L2DecodeSurfaceHandler {
+ public:
+  // Constructor for the stateless backend. Arguments are:
+  // |client| the decoder we will be backing.
+  // |device| the V4L2 decoder device.
+  // |frame_pool| pool from which to get backing memory for decoded frames.
+  // |profile| profile of the codec we will decode.
+  // |task_runner| the decoder task runner, to which we will post our tasks.
+  V4L2StatelessVideoDecoderBackend(
+      Client* const client,
+      scoped_refptr<V4L2Device> device,
+      DmabufVideoFramePool* const frame_pool,
+      VideoCodecProfile profile,
+      scoped_refptr<base::SequencedTaskRunner> task_runner);
+
+  ~V4L2StatelessVideoDecoderBackend() override;
+
+  // V4L2VideoDecoderBackend implementation
+  bool Initialize() override;
+  void EnqueueDecodeTask(scoped_refptr<DecoderBuffer> buffer,
+                         VideoDecoder::DecodeCB decode_cb,
+                         int32_t bitstream_id) override;
+  void OnOutputBufferDequeued(V4L2ReadableBufferRef buffer) override;
+  void OnStreamStopped() override;
+  void ClearPendingRequests(DecodeStatus status) override;
+
+  // V4L2DecodeSurfaceHandler implementation.
+  scoped_refptr<V4L2DecodeSurface> CreateSurface() override;
+  bool SubmitSlice(const scoped_refptr<V4L2DecodeSurface>& dec_surface,
+                   const uint8_t* data,
+                   size_t size) override;
+  void DecodeSurface(
+      const scoped_refptr<V4L2DecodeSurface>& dec_surface) override;
+  void SurfaceReady(const scoped_refptr<V4L2DecodeSurface>& dec_surface,
+                    int32_t bitstream_id,
+                    const gfx::Rect& visible_rect,
+                    const VideoColorSpace& color_space) override;
+
+ private:
+  // Request for displaying the surface or calling the decode callback.
+  struct OutputRequest;
+
+  // Request for decoding buffer. Every EnqueueDecodeTask() call generates 1
+  // DecodeRequest.
+  struct DecodeRequest {
+    // The decode buffer passed to EnqueueDecodeTask().
+    scoped_refptr<DecoderBuffer> buffer;
+    // The callback function passed to EnqueueDecodeTask().
+    VideoDecoder::DecodeCB decode_cb;
+    // The identifier for the decoder buffer.
+    int32_t bitstream_id;
+
+    DecodeRequest(scoped_refptr<DecoderBuffer> buf,
+                  VideoDecoder::DecodeCB cb,
+                  int32_t id);
+
+    // Allow move, but not copy
+    DecodeRequest(DecodeRequest&&);
+    DecodeRequest& operator=(DecodeRequest&&);
+
+    ~DecodeRequest();
+
+    DISALLOW_COPY_AND_ASSIGN(DecodeRequest);
+  };
+
+  // The reason the decoding is paused.
+  enum class PauseReason {
+    // Not stopped, decoding normally.
+    kNone,
+    // Cannot create a new V4L2 surface. Waiting for surfaces to be released.
+    kRanOutOfSurfaces,
+    // A VP9 superframe contains multiple subframes. Before decoding the next
+    // subframe, we need to wait for previous subframes decoded and update the
+    // context.
+    kWaitSubFrameDecoded,
+  };
+
+  // Callback which is called when V4L2 surface is destroyed.
+  void ReuseOutputBuffer(V4L2ReadableBufferRef buffer);
+
+  // Try to advance the decoding work.
+  void DoDecodeWork();
+  // Try to decode buffer from the pending decode request queue.
+  // This method stops decoding when:
+  // - Run out of surface
+  // - Flushing or changing resolution
+  // Invoke this method again when these situation ends.
+  bool PumpDecodeTask();
+  // Try to output surface from |output_request_queue_|.
+  // This method stops outputting surface when the first surface is not dequeued
+  // from the V4L2 device. Invoke this method again when any surface is
+  // dequeued from the V4L2 device.
+  void PumpOutputSurfaces();
+  // Setup the format of V4L2 output buffer, and allocate new buffer set.
+  bool ChangeResolution();
+
+  // Check whether request api is supported or not.
+  bool CheckRequestAPISupport();
+  // Allocate necessary request buffers is request api is supported.
+  bool AllocateRequests();
+
+  // Video frame pool provided by the decoder.
+  DmabufVideoFramePool* const frame_pool_;
+
+  // Video profile we will be decoding.
+  const VideoCodecProfile profile_;
+
+  // Video decoder used to parse stream headers by software.
+  std::unique_ptr<AcceleratedVideoDecoder> avd_;
+
+  // The decode request which is currently processed.
+  base::Optional<DecodeRequest> current_decode_request_;
+  // Surfaces enqueued to V4L2 device. Since we are stateless, they are
+  // guaranteed to be proceeded in FIFO order.
+  base::queue<scoped_refptr<V4L2DecodeSurface>> surfaces_at_device_;
+
+  // Queue of pending decode request.
+  base::queue<DecodeRequest> decode_request_queue_;
+
+  // Queue of pending output request.
+  base::queue<OutputRequest> output_request_queue_;
+
+  // Indicates why decoding is currently paused.
+  PauseReason pause_reason_ = PauseReason::kNone;
+
+  // The time at which each buffer decode operation started. Not each decode
+  // operation leads to a frame being output and frames might be reordered, so
+  // we don't know when it's safe to drop a timestamp. This means we need to use
+  // a cache here, with a size large enough to account for frame reordering.
+  base::MRUCache<int32_t, base::TimeDelta> bitstream_id_to_timestamp_;
+
+  // The task runner we are running on, for convenience.
+  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+  // Callbacks of EOS buffer passed from Decode().
+  VideoDecoder::DecodeCB flush_cb_;
+
+  // Set to true during Initialize() if the codec driver supports request API.
+  bool supports_requests_ = false;
+  // FIFO queue of requests, only used if supports_requests_ is true.
+  base::queue<base::ScopedFD> requests_;
+  // Stores the media file descriptor, only used if supports_requests_ is true.
+  base::ScopedFD media_fd_;
+
+  base::WeakPtr<V4L2StatelessVideoDecoderBackend> weak_this_;
+  base::WeakPtrFactory<V4L2StatelessVideoDecoderBackend> weak_this_factory_{
+      this};
+
+  DISALLOW_COPY_AND_ASSIGN(V4L2StatelessVideoDecoderBackend);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_GPU_V4L2_V4L2_VIDEO_DECODER_BACKEND_STATELESS_H_
diff --git a/media/mojo/clients/mojo_cdm.cc b/media/mojo/clients/mojo_cdm.cc
index da2a4e4..908020a 100644
--- a/media/mojo/clients/mojo_cdm.cc
+++ b/media/mojo/clients/mojo_cdm.cc
@@ -41,7 +41,7 @@
     const std::string& key_system,
     const url::Origin& security_origin,
     const CdmConfig& cdm_config,
-    mojom::ContentDecryptionModulePtr remote_cdm,
+    mojo::PendingRemote<mojom::ContentDecryptionModule> remote_cdm,
     mojom::InterfaceFactory* interface_factory,
     const SessionMessageCB& session_message_cb,
     const SessionClosedCB& session_closed_cb,
@@ -60,7 +60,7 @@
                           std::move(promise));
 }
 
-MojoCdm::MojoCdm(mojom::ContentDecryptionModulePtr remote_cdm,
+MojoCdm::MojoCdm(mojo::PendingRemote<mojom::ContentDecryptionModule> remote_cdm,
                  mojom::InterfaceFactory* interface_factory,
                  const SessionMessageCB& session_message_cb,
                  const SessionClosedCB& session_closed_cb,
@@ -116,7 +116,7 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   // If connection error has happened, fail immediately.
-  if (remote_cdm_.encountered_error()) {
+  if (!remote_cdm_.is_connected()) {
     LOG(ERROR) << "Remote CDM encountered error.";
     promise->reject(CdmPromise::Exception::INVALID_STATE_ERROR, 0,
                     "Mojo CDM creation failed.");
@@ -127,7 +127,7 @@
   RecordConnectionError(false);
 
   // Otherwise, set an error handler to catch the connection error.
-  remote_cdm_.set_connection_error_with_reason_handler(
+  remote_cdm_.set_disconnect_with_reason_handler(
       base::Bind(&MojoCdm::OnConnectionError, base::Unretained(this)));
 
   pending_init_promise_ = std::move(promise);
diff --git a/media/mojo/clients/mojo_cdm.h b/media/mojo/clients/mojo_cdm.h
index a9f8fec..981003eb 100644
--- a/media/mojo/clients/mojo_cdm.h
+++ b/media/mojo/clients/mojo_cdm.h
@@ -23,6 +23,8 @@
 #include "media/mojo/mojom/content_decryption_module.mojom.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace base {
 class SingleThreadTaskRunner;
@@ -53,7 +55,7 @@
       const std::string& key_system,
       const url::Origin& security_origin,
       const CdmConfig& cdm_config,
-      mojom::ContentDecryptionModulePtr remote_cdm,
+      mojo::PendingRemote<mojom::ContentDecryptionModule> remote_cdm,
       mojom::InterfaceFactory* interface_factory,
       const SessionMessageCB& session_message_cb,
       const SessionClosedCB& session_closed_cb,
@@ -89,7 +91,7 @@
   int GetCdmId() const final;
 
  private:
-  MojoCdm(mojom::ContentDecryptionModulePtr remote_cdm,
+  MojoCdm(mojo::PendingRemote<mojom::ContentDecryptionModule> remote_cdm,
           mojom::InterfaceFactory* interface_factory,
           const SessionMessageCB& session_message_cb,
           const SessionClosedCB& session_closed_cb,
@@ -138,7 +140,7 @@
 
   THREAD_CHECKER(thread_checker_);
 
-  mojom::ContentDecryptionModulePtr remote_cdm_;
+  mojo::Remote<mojom::ContentDecryptionModule> remote_cdm_;
   mojom::InterfaceFactory* interface_factory_;
   mojo::AssociatedBinding<ContentDecryptionModuleClient> client_binding_;
 
diff --git a/media/mojo/clients/mojo_cdm_factory.cc b/media/mojo/clients/mojo_cdm_factory.cc
index 93db446..d4b3cdd9 100644
--- a/media/mojo/clients/mojo_cdm_factory.cc
+++ b/media/mojo/clients/mojo_cdm_factory.cc
@@ -58,13 +58,14 @@
     return;
   }
 
-  mojom::ContentDecryptionModulePtr cdm_ptr;
-  interface_factory_->CreateCdm(key_system, mojo::MakeRequest(&cdm_ptr));
+  mojo::PendingRemote<mojom::ContentDecryptionModule> cdm_pending_remote;
+  interface_factory_->CreateCdm(
+      key_system, cdm_pending_remote.InitWithNewPipeAndPassReceiver());
 
-  MojoCdm::Create(key_system, security_origin, cdm_config, std::move(cdm_ptr),
-                  interface_factory_, session_message_cb, session_closed_cb,
-                  session_keys_change_cb, session_expiration_update_cb,
-                  cdm_created_cb);
+  MojoCdm::Create(key_system, security_origin, cdm_config,
+                  std::move(cdm_pending_remote), interface_factory_,
+                  session_message_cb, session_closed_cb, session_keys_change_cb,
+                  session_expiration_update_cb, cdm_created_cb);
 }
 
 }  // namespace media
diff --git a/media/mojo/clients/mojo_cdm_unittest.cc b/media/mojo/clients/mojo_cdm_unittest.cc
index 5ad59778..73db7436 100644
--- a/media/mojo/clients/mojo_cdm_unittest.cc
+++ b/media/mojo/clients/mojo_cdm_unittest.cc
@@ -21,6 +21,7 @@
 #include "media/mojo/services/mojo_cdm_service.h"
 #include "media/mojo/services/mojo_cdm_service_context.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -80,10 +81,9 @@
     // TODO(xhwang): Add pending init support.
     DCHECK_NE(PENDING, expected_result);
 
-    mojom::ContentDecryptionModulePtr remote_cdm;
-    auto cdm_request = mojo::MakeRequest(&remote_cdm);
+    mojo::PendingRemote<mojom::ContentDecryptionModule> remote_cdm;
 
-    cdm_binding_.Bind(std::move(cdm_request));
+    cdm_binding_.Bind(remote_cdm.InitWithNewPipeAndPassReceiver());
 
     std::string key_system;
     if (expected_result == CONNECTION_ERROR_BEFORE) {
diff --git a/media/mojo/services/cdm_service.cc b/media/mojo/services/cdm_service.cc
index 0c1d80e6..d8de566a 100644
--- a/media/mojo/services/cdm_service.cc
+++ b/media/mojo/services/cdm_service.cc
@@ -103,7 +103,7 @@
       std::move(destroy_cb_).Run();
   }
 
-  // Must be declared before the bindings below because the bound objects might
+  // Must be declared before the receivers below because the bound objects might
   // take a raw pointer of |cdm_service_context_| and assume it's always
   // available.
   MojoCdmServiceContext cdm_service_context_;
diff --git a/mojo/public/cpp/bindings/remote_set.h b/mojo/public/cpp/bindings/remote_set.h
index 0e90994..d463fe2 100644
--- a/mojo/public/cpp/bindings/remote_set.h
+++ b/mojo/public/cpp/bindings/remote_set.h
@@ -121,6 +121,8 @@
   void Clear() { storage_.clear(); }
 
   bool empty() const { return storage_.empty(); }
+  size_t size() const { return storage_.size(); }
+
   Iterator begin() { return Iterator(storage_.begin()); }
   Iterator begin() const { return Iterator(storage_.begin()); }
   Iterator end() { return Iterator(storage_.end()); }
diff --git a/net/http/bidirectional_stream_unittest.cc b/net/http/bidirectional_stream_unittest.cc
index 34136bc..0e8e18c3c 100644
--- a/net/http/bidirectional_stream_unittest.cc
+++ b/net/http/bidirectional_stream_unittest.cc
@@ -433,7 +433,8 @@
     http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
     SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
                        PRIVACY_MODE_DISABLED,
-                       SpdySessionKey::IsProxySession::kFalse, socket_tag);
+                       SpdySessionKey::IsProxySession::kFalse, socket_tag,
+                       NetworkIsolationKey(), false /* disable_secure_dns */);
     session_ = CreateSpdySession(http_session_.get(), key, net_log_.bound());
   }
 
@@ -627,7 +628,8 @@
   http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
   SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
   std::unique_ptr<BidirectionalStreamRequestInfo> request_info(
       new BidirectionalStreamRequestInfo);
   request_info->method = "GET";
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 0c1a199..5fcb4c0 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -5488,7 +5488,8 @@
   session_deps_.host_resolver->set_ondemand_mode(false);
   SpdySessionKey key(HostPortPair("proxy", 70), ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kTrue, SocketTag());
+                     SpdySessionKey::IsProxySession::kTrue, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session =
       CreateSpdySession(session.get(), key, log.bound());
 
@@ -11334,7 +11335,9 @@
           "http://www.example.org/direct",
           ClientSocketPool::GroupId(HostPortPair("www.example.org", 80),
                                     ClientSocketPool::SocketType::kHttp,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+                                    PrivacyMode::PRIVACY_MODE_DISABLED,
+                                    NetworkIsolationKey(),
+                                    false /* disable_secure_dns */),
           false,
       },
       {
@@ -11342,7 +11345,9 @@
           "http://[2001:1418:13:1::25]/direct",
           ClientSocketPool::GroupId(HostPortPair("2001:1418:13:1::25", 80),
                                     ClientSocketPool::SocketType::kHttp,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+                                    PrivacyMode::PRIVACY_MODE_DISABLED,
+                                    NetworkIsolationKey(),
+                                    false /* disable_secure_dns */),
           false,
       },
 
@@ -11352,7 +11357,9 @@
           "https://www.example.org/direct_ssl",
           ClientSocketPool::GroupId(HostPortPair("www.example.org", 443),
                                     ClientSocketPool::SocketType::kSsl,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+                                    PrivacyMode::PRIVACY_MODE_DISABLED,
+                                    NetworkIsolationKey(),
+                                    false /* disable_secure_dns */),
           true,
       },
       {
@@ -11360,7 +11367,9 @@
           "https://[2001:1418:13:1::25]/direct",
           ClientSocketPool::GroupId(HostPortPair("2001:1418:13:1::25", 443),
                                     ClientSocketPool::SocketType::kSsl,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+                                    PrivacyMode::PRIVACY_MODE_DISABLED,
+                                    NetworkIsolationKey(),
+                                    false /* disable_secure_dns */),
           true,
       },
       {
@@ -11368,7 +11377,9 @@
           "https://host.with.alternate/direct",
           ClientSocketPool::GroupId(HostPortPair("host.with.alternate", 443),
                                     ClientSocketPool::SocketType::kSsl,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+                                    PrivacyMode::PRIVACY_MODE_DISABLED,
+                                    NetworkIsolationKey(),
+                                    false /* disable_secure_dns */),
           true,
       },
   };
@@ -11403,7 +11414,9 @@
           "http://www.example.org/http_proxy_normal",
           ClientSocketPool::GroupId(HostPortPair("www.example.org", 80),
                                     ClientSocketPool::SocketType::kHttp,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+                                    PrivacyMode::PRIVACY_MODE_DISABLED,
+                                    NetworkIsolationKey(),
+                                    false /* disable_secure_dns */),
           false,
       },
 
@@ -11413,7 +11426,9 @@
           "https://www.example.org/http_connect_ssl",
           ClientSocketPool::GroupId(HostPortPair("www.example.org", 443),
                                     ClientSocketPool::SocketType::kSsl,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+                                    PrivacyMode::PRIVACY_MODE_DISABLED,
+                                    NetworkIsolationKey(),
+                                    false /* disable_secure_dns */),
           true,
       },
 
@@ -11422,7 +11437,9 @@
           "https://host.with.alternate/direct",
           ClientSocketPool::GroupId(HostPortPair("host.with.alternate", 443),
                                     ClientSocketPool::SocketType::kSsl,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+                                    PrivacyMode::PRIVACY_MODE_DISABLED,
+                                    NetworkIsolationKey(),
+                                    false /* disable_secure_dns */),
           true,
       },
   };
@@ -11459,7 +11476,9 @@
           "http://www.example.org/socks4_direct",
           ClientSocketPool::GroupId(HostPortPair("www.example.org", 80),
                                     ClientSocketPool::SocketType::kHttp,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+                                    PrivacyMode::PRIVACY_MODE_DISABLED,
+                                    NetworkIsolationKey(),
+                                    false /* disable_secure_dns */),
           false,
       },
       {
@@ -11467,7 +11486,9 @@
           "http://www.example.org/socks5_direct",
           ClientSocketPool::GroupId(HostPortPair("www.example.org", 80),
                                     ClientSocketPool::SocketType::kHttp,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+                                    PrivacyMode::PRIVACY_MODE_DISABLED,
+                                    NetworkIsolationKey(),
+                                    false /* disable_secure_dns */),
           false,
       },
 
@@ -11477,7 +11498,9 @@
           "https://www.example.org/socks4_ssl",
           ClientSocketPool::GroupId(HostPortPair("www.example.org", 443),
                                     ClientSocketPool::SocketType::kSsl,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+                                    PrivacyMode::PRIVACY_MODE_DISABLED,
+                                    NetworkIsolationKey(),
+                                    false /* disable_secure_dns */),
           true,
       },
       {
@@ -11485,7 +11508,9 @@
           "https://www.example.org/socks5_ssl",
           ClientSocketPool::GroupId(HostPortPair("www.example.org", 443),
                                     ClientSocketPool::SocketType::kSsl,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+                                    PrivacyMode::PRIVACY_MODE_DISABLED,
+                                    NetworkIsolationKey(),
+                                    false /* disable_secure_dns */),
           true,
       },
 
@@ -11494,7 +11519,9 @@
           "https://host.with.alternate/direct",
           ClientSocketPool::GroupId(HostPortPair("host.with.alternate", 443),
                                     ClientSocketPool::SocketType::kSsl,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+                                    PrivacyMode::PRIVACY_MODE_DISABLED,
+                                    NetworkIsolationKey(),
+                                    false /* disable_secure_dns */),
           true,
       },
   };
@@ -13612,7 +13639,8 @@
   HostPortPair host_port_pair("www.example.org", 443);
   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session =
       CreateSpdySession(session.get(), key, NetLogWithSource());
 
@@ -14673,7 +14701,8 @@
 
   const ClientSocketPool::GroupId kSocketGroup(
       HostPortPair("www.example.com", 80), ClientSocketPool::SocketType::kHttp,
-      PrivacyMode::PRIVACY_MODE_DISABLED);
+      PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+      false /* disable_secure_dns */);
 
   // First round of authentication.
   auth_handler->SetGenerateExpectation(false, OK);
@@ -15283,7 +15312,8 @@
   HostPortPair host_port_pair("www.example.org", 443);
   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session =
       CreateSpdySession(session.get(), key, NetLogWithSource());
 
@@ -17040,7 +17070,8 @@
   HostPortPair host_port_pair_a("www.a.com", 443);
   SpdySessionKey spdy_session_key_a(
       host_port_pair_a, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+      NetworkIsolationKey(), false /* disable_secure_dns */);
   EXPECT_FALSE(
       HasSpdySession(session->spdy_session_pool(), spdy_session_key_a));
 
@@ -17075,7 +17106,8 @@
   HostPortPair host_port_pair_b("www.b.com", 443);
   SpdySessionKey spdy_session_key_b(
       host_port_pair_b, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+      NetworkIsolationKey(), false /* disable_secure_dns */);
   EXPECT_FALSE(
       HasSpdySession(session->spdy_session_pool(), spdy_session_key_b));
   HttpRequestInfo request2;
@@ -17107,7 +17139,8 @@
   HostPortPair host_port_pair_a1("www.a.com", 80);
   SpdySessionKey spdy_session_key_a1(
       host_port_pair_a1, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+      NetworkIsolationKey(), false /* disable_secure_dns */);
   EXPECT_FALSE(
       HasSpdySession(session->spdy_session_pool(), spdy_session_key_a1));
   HttpRequestInfo request3;
diff --git a/net/http/http_stream_factory_job_controller_unittest.cc b/net/http/http_stream_factory_job_controller_unittest.cc
index 8154781..d49c9945 100644
--- a/net/http/http_stream_factory_job_controller_unittest.cc
+++ b/net/http/http_stream_factory_job_controller_unittest.cc
@@ -2659,10 +2659,11 @@
   // Sanity check - make sure the SpdySession was created.
   base::WeakPtr<SpdySession> spdy_session =
       session_->spdy_session_pool()->FindAvailableSession(
-          SpdySessionKey(HostPortPair::FromURL(request_info.url),
-                         ProxyServer::Direct(), request_info.privacy_mode,
-                         SpdySessionKey::IsProxySession::kFalse,
-                         request_info.socket_tag),
+          SpdySessionKey(
+              HostPortPair::FromURL(request_info.url), ProxyServer::Direct(),
+              request_info.privacy_mode, SpdySessionKey::IsProxySession::kFalse,
+              request_info.socket_tag, request_info.network_isolation_key,
+              request_info.disable_secure_dns),
           false /* enable_ip_based_pooling */, false /* is_websocket */,
           NetLogWithSource());
   EXPECT_TRUE(spdy_session);
@@ -2805,18 +2806,18 @@
   TransportClientSocketPool* socket_pool =
       reinterpret_cast<TransportClientSocketPool*>(session_->GetSocketPool(
           HttpNetworkSession::NORMAL_SOCKET_POOL, ProxyServer::Direct()));
-  ClientSocketPool::GroupId group_id0(HostPortPair::FromURL(request_info.url),
-                                      ClientSocketPool::SocketType::kSsl,
-                                      request_info.privacy_mode,
-                                      NetworkIsolationKey());
-  ClientSocketPool::GroupId group_id1(HostPortPair::FromURL(request_info.url),
-                                      ClientSocketPool::SocketType::kSsl,
-                                      request_info.privacy_mode,
-                                      kNetworkIsolationKey1);
-  ClientSocketPool::GroupId group_id2(HostPortPair::FromURL(request_info.url),
-                                      ClientSocketPool::SocketType::kSsl,
-                                      request_info.privacy_mode,
-                                      kNetworkIsolationKey2);
+  ClientSocketPool::GroupId group_id0(
+      HostPortPair::FromURL(request_info.url),
+      ClientSocketPool::SocketType::kSsl, request_info.privacy_mode,
+      NetworkIsolationKey(), false /* disable_secure_dns */);
+  ClientSocketPool::GroupId group_id1(
+      HostPortPair::FromURL(request_info.url),
+      ClientSocketPool::SocketType::kSsl, request_info.privacy_mode,
+      kNetworkIsolationKey1, false /* disable_secure_dns */);
+  ClientSocketPool::GroupId group_id2(
+      HostPortPair::FromURL(request_info.url),
+      ClientSocketPool::SocketType::kSsl, request_info.privacy_mode,
+      kNetworkIsolationKey2, false /* disable_secure_dns */);
   EXPECT_EQ(static_cast<uint32_t>(kNumRequests),
             socket_pool->NumConnectJobsInGroupForTesting(group_id0));
   EXPECT_EQ(1u, socket_pool->NumConnectJobsInGroupForTesting(group_id1));
diff --git a/net/http/http_stream_factory_unittest.cc b/net/http/http_stream_factory_unittest.cc
index 6c4c8d0..870d6954 100644
--- a/net/http/http_stream_factory_unittest.cc
+++ b/net/http/http_stream_factory_unittest.cc
@@ -392,13 +392,15 @@
 
 ClientSocketPool::GroupId GetGroupId(const TestCase& test) {
   if (test.ssl) {
-    return ClientSocketPool::GroupId(HostPortPair("www.google.com", 443),
-                                     ClientSocketPool::SocketType::kSsl,
-                                     PrivacyMode::PRIVACY_MODE_DISABLED);
+    return ClientSocketPool::GroupId(
+        HostPortPair("www.google.com", 443), ClientSocketPool::SocketType::kSsl,
+        PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+        false /* disable_secure_dns */);
   }
-  return ClientSocketPool::GroupId(HostPortPair("www.google.com", 80),
-                                   ClientSocketPool::SocketType::kHttp,
-                                   PrivacyMode::PRIVACY_MODE_DISABLED);
+  return ClientSocketPool::GroupId(
+      HostPortPair("www.google.com", 80), ClientSocketPool::SocketType::kHttp,
+      PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+      false /* disable_secure_dns */);
 }
 
 class CapturePreconnectsTransportSocketPool : public TransportClientSocketPool {
@@ -424,7 +426,8 @@
     // Group ID that shouldn't match much.
     last_group_id_ = ClientSocketPool::GroupId(
         HostPortPair(), ClientSocketPool::SocketType::kSsl,
-        PrivacyMode::PRIVACY_MODE_ENABLED);
+        PrivacyMode::PRIVACY_MODE_ENABLED, NetworkIsolationKey(),
+        false /* disable_secure_dns */);
   }
 
   int RequestSocket(
@@ -571,7 +574,8 @@
     HostPortPair host_port_pair("www.google.com", 443);
     SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
                        PRIVACY_MODE_DISABLED,
-                       SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                       SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                       NetworkIsolationKey(), false /* disable_secure_dns */);
     ignore_result(CreateFakeSpdySession(session->spdy_session_pool(), key));
 
     CommonConnectJobParams common_connect_job_params =
@@ -1997,9 +2001,10 @@
         base::MakeRefCounted<ClientSocketPool::SocketParams>(
             std::make_unique<SSLConfig>() /* ssl_config_for_origin */,
             nullptr /* ssl_config_for_proxy */);
-    ClientSocketPool::GroupId group_id(host_port_pair,
-                                       ClientSocketPool::SocketType::kSsl,
-                                       PrivacyMode::PRIVACY_MODE_DISABLED);
+    ClientSocketPool::GroupId group_id(
+        host_port_pair, ClientSocketPool::SocketType::kSsl,
+        PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+        false /* disable_secure_dns */);
     int rv = connection->Init(
         group_id, socket_params, base::nullopt /* proxy_annotation_tag */,
         MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
diff --git a/net/quic/bidirectional_stream_quic_impl_unittest.cc b/net/quic/bidirectional_stream_quic_impl_unittest.cc
index 89e53f39..70b02f5 100644
--- a/net/quic/bidirectional_stream_quic_impl_unittest.cc
+++ b/net/quic/bidirectional_stream_quic_impl_unittest.cc
@@ -546,7 +546,8 @@
         &transport_security_state_, /*ssl_config_service=*/nullptr,
         base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)),
         QuicSessionKey(kDefaultServerHostName, kDefaultServerPort,
-                       PRIVACY_MODE_DISABLED, SocketTag()),
+                       PRIVACY_MODE_DISABLED, SocketTag(),
+                       NetworkIsolationKey(), false /* disable_secure_dns */),
         /*require_confirmation=*/false,
         /*max_allowed_push_id=*/0,
         /*migrate_session_early_v2=*/false,
diff --git a/net/quic/quic_chromium_client_session_test.cc b/net/quic/quic_chromium_client_session_test.cc
index a30491b..1227ef7 100644
--- a/net/quic/quic_chromium_client_session_test.cc
+++ b/net/quic/quic_chromium_client_session_test.cc
@@ -129,7 +129,9 @@
         session_key_(kServerHostname,
                      kServerPort,
                      PRIVACY_MODE_DISABLED,
-                     SocketTag()),
+                     SocketTag(),
+                     NetworkIsolationKey(),
+                     false /* disable_secure_dns */),
         destination_(kServerHostname, kServerPort),
         client_maker_(version_,
                       quic::QuicUtils::CreateRandomConnectionId(&random_),
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 74e87cf..8b2949f 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -354,7 +354,8 @@
         &transport_security_state_, /*ssl_config_service=*/nullptr,
         base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)),
         QuicSessionKey(kDefaultServerHostName, kDefaultServerPort,
-                       PRIVACY_MODE_DISABLED, SocketTag()),
+                       PRIVACY_MODE_DISABLED, SocketTag(),
+                       NetworkIsolationKey(), false /* disable_secure_dns */),
         /*require_confirmation=*/false,
         /*max_allowed_push_id=*/0,
         /*migrate_session_early_v2=*/false,
diff --git a/net/quic/quic_proxy_client_socket_unittest.cc b/net/quic/quic_proxy_client_socket_unittest.cc
index 96d156a..7cbdda04 100644
--- a/net/quic/quic_proxy_client_socket_unittest.cc
+++ b/net/quic/quic_proxy_client_socket_unittest.cc
@@ -247,7 +247,8 @@
         &transport_security_state_, /*ssl_config_service=*/nullptr,
         base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)),
         QuicSessionKey("mail.example.org", 80, PRIVACY_MODE_DISABLED,
-                       SocketTag()),
+                       SocketTag(), NetworkIsolationKey(),
+                       false /* disable_secure_dns */),
         /*require_confirmation=*/false,
         /*max_allowed_push_id=*/0,
         /*migrate_session_early_v2=*/false,
diff --git a/net/quic/quic_session_key.h b/net/quic/quic_session_key.h
index a8987ec..a561aab 100644
--- a/net/quic/quic_session_key.h
+++ b/net/quic/quic_session_key.h
@@ -17,27 +17,22 @@
 // tag.
 class QUIC_EXPORT_PRIVATE QuicSessionKey {
  public:
-  // TODO(mmenke): Remove default NetworkIsolationKey() values, which are only
-  // used in tests.
   QuicSessionKey();
-  QuicSessionKey(
-      const HostPortPair& host_port_pair,
-      PrivacyMode privacy_mode,
-      const SocketTag& socket_tag,
-      const NetworkIsolationKey& network_isolation_key = NetworkIsolationKey(),
-      bool disable_secure_dns = false);
-  QuicSessionKey(
-      const std::string& host,
-      uint16_t port,
-      PrivacyMode privacy_mode,
-      const SocketTag& socket_tag,
-      const NetworkIsolationKey& network_isolation_key = NetworkIsolationKey(),
-      bool disable_secure_dns = false);
-  QuicSessionKey(
-      const quic::QuicServerId& server_id,
-      const SocketTag& socket_tag,
-      const NetworkIsolationKey& network_isolation_key = NetworkIsolationKey(),
-      bool disable_secure_dns = false);
+  QuicSessionKey(const HostPortPair& host_port_pair,
+                 PrivacyMode privacy_mode,
+                 const SocketTag& socket_tag,
+                 const NetworkIsolationKey& network_isolation_key,
+                 bool disable_secure_dns);
+  QuicSessionKey(const std::string& host,
+                 uint16_t port,
+                 PrivacyMode privacy_mode,
+                 const SocketTag& socket_tag,
+                 const NetworkIsolationKey& network_isolation_key,
+                 bool disable_secure_dns);
+  QuicSessionKey(const quic::QuicServerId& server_id,
+                 const SocketTag& socket_tag,
+                 const NetworkIsolationKey& network_isolation_key,
+                 bool disable_secure_dns);
   QuicSessionKey(const QuicSessionKey& other);
   ~QuicSessionKey() = default;
 
diff --git a/net/socket/client_socket_pool.h b/net/socket/client_socket_pool.h
index 0790c8f..94f900d 100644
--- a/net/socket/client_socket_pool.h
+++ b/net/socket/client_socket_pool.h
@@ -109,13 +109,11 @@
   class NET_EXPORT GroupId {
    public:
     GroupId();
-    // TODO(mmenke): Remove default |network_isolation_key| value (only used by
-    // tests).
     GroupId(const HostPortPair& destination,
             SocketType socket_type,
             PrivacyMode privacy_mode,
-            NetworkIsolationKey network_isolation_key = NetworkIsolationKey(),
-            bool disable_secure_dns = false);
+            NetworkIsolationKey network_isolation_key,
+            bool disable_secure_dns);
     GroupId(const GroupId& group_id);
 
     ~GroupId();
diff --git a/net/socket/client_socket_pool_unittest.cc b/net/socket/client_socket_pool_unittest.cc
index d243745e..1c75c9b 100644
--- a/net/socket/client_socket_pool_unittest.cc
+++ b/net/socket/client_socket_pool_unittest.cc
@@ -169,12 +169,14 @@
     ClientSocketPool::GroupId group_id1(
         HostPortPair("foo", 443), ClientSocketPool::SocketType::kSsl,
         PrivacyMode::PRIVACY_MODE_DISABLED,
-        NetworkIsolationKey(kOriginFoo, kOriginFoo));
+        NetworkIsolationKey(kOriginFoo, kOriginFoo),
+        false /* disable_secure_dns */);
 
     ClientSocketPool::GroupId group_id2(
         HostPortPair("foo", 443), ClientSocketPool::SocketType::kSsl,
         PrivacyMode::PRIVACY_MODE_DISABLED,
-        NetworkIsolationKey(kOriginBar, kOriginBar));
+        NetworkIsolationKey(kOriginBar, kOriginBar),
+        false /* disable_secure_dns */);
 
     EXPECT_FALSE(group_id1.network_isolation_key().IsFullyPopulated());
     EXPECT_FALSE(group_id2.network_isolation_key().IsFullyPopulated());
diff --git a/net/socket/transport_client_socket_pool_unittest.cc b/net/socket/transport_client_socket_pool_unittest.cc
index 065ab22..507ac4a8 100644
--- a/net/socket/transport_client_socket_pool_unittest.cc
+++ b/net/socket/transport_client_socket_pool_unittest.cc
@@ -103,7 +103,9 @@
             TransportClientSocketPool::set_connect_backup_jobs_enabled(true)),
         group_id_(HostPortPair("www.google.com", 80),
                   ClientSocketPool::SocketType::kHttp,
-                  PrivacyMode::PRIVACY_MODE_DISABLED),
+                  PrivacyMode::PRIVACY_MODE_DISABLED,
+                  NetworkIsolationKey(),
+                  false /* disable_secure_dns */),
         params_(ClientSocketPool::SocketParams::CreateForHttpForTesting()),
         client_socket_factory_(&net_log_) {
     std::unique_ptr<MockCertVerifier> cert_verifier =
@@ -149,9 +151,10 @@
   }
 
   int StartRequest(const std::string& host_name, RequestPriority priority) {
-    ClientSocketPool::GroupId group_id(HostPortPair(host_name, 80),
-                                       ClientSocketPool::SocketType::kHttp,
-                                       PrivacyMode::PRIVACY_MODE_DISABLED);
+    ClientSocketPool::GroupId group_id(
+        HostPortPair(host_name, 80), ClientSocketPool::SocketType::kHttp,
+        PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+        false /* disable_secure_dns */);
     return test_base_.StartRequestUsingPool(
         pool_.get(), group_id, priority,
         ClientSocketPool::RespectLimits::ENABLED,
@@ -1043,9 +1046,10 @@
   ClientSocketHandle handle;
   TestCompletionCallback callback;
   int rv =
-      handle.Init(ClientSocketPool::GroupId(kHostPortPair,
-                                            ClientSocketPool::SocketType::kSsl,
-                                            PrivacyMode::PRIVACY_MODE_DISABLED),
+      handle.Init(ClientSocketPool::GroupId(
+                      kHostPortPair, ClientSocketPool::SocketType::kSsl,
+                      PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+                      false /* disable_secure_dns */),
                   socket_params, base::nullopt /* proxy_annotation_tag */,
                   MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
                   callback.callback(), ClientSocketPool::ProxyAuthCallback(),
@@ -1320,9 +1324,10 @@
     ClientSocketHandle handle;
     TestCompletionCallback callback;
     int rv = handle.Init(
-        ClientSocketPool::GroupId(kDestination,
-                                  ClientSocketPool::SocketType::kHttp,
-                                  PrivacyMode::PRIVACY_MODE_DISABLED),
+        ClientSocketPool::GroupId(
+            kDestination, ClientSocketPool::SocketType::kHttp,
+            PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+            false /* disable_secure_dns */),
         socket_params, TRAFFIC_ANNOTATION_FOR_TESTS, LOW, SocketTag(),
         ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
         ClientSocketPool::ProxyAuthCallback(), &proxy_pool, NetLogWithSource());
@@ -1386,9 +1391,10 @@
           std::make_unique<SSLConfig>() /* ssl_config_for_origin */,
           std::make_unique<SSLConfig>() /* ssl_config_for_proxy */);
 
-  ClientSocketPool::GroupId group_id(kEndpoint,
-                                     ClientSocketPool::SocketType::kSsl,
-                                     PrivacyMode::PRIVACY_MODE_DISABLED);
+  ClientSocketPool::GroupId group_id(
+      kEndpoint, ClientSocketPool::SocketType::kSsl,
+      PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+      false /* disable_secure_dns */);
 
   // Start the first connection attempt.
   TestCompletionCallback callback1;
@@ -1489,9 +1495,10 @@
           std::make_unique<SSLConfig>() /* ssl_config_for_origin */,
           std::make_unique<SSLConfig>() /* ssl_config_for_proxy */);
 
-  ClientSocketPool::GroupId group_id(kEndpoint,
-                                     ClientSocketPool::SocketType::kSsl,
-                                     PrivacyMode::PRIVACY_MODE_DISABLED);
+  ClientSocketPool::GroupId group_id(
+      kEndpoint, ClientSocketPool::SocketType::kSsl,
+      PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+      false /* disable_secure_dns */);
 
   // Start the first connection attempt.
   TestCompletionCallback callback1;
@@ -1586,9 +1593,10 @@
               std::make_unique<SSLConfig>() /* ssl_config_for_proxy */);
 
       int rv = handle.Init(
-          ClientSocketPool::GroupId(kEndpoint,
-                                    ClientSocketPool::SocketType::kSsl,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+          ClientSocketPool::GroupId(
+              kEndpoint, ClientSocketPool::SocketType::kSsl,
+              PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+              false /* disable_secure_dns */),
           socket_params, TRAFFIC_ANNOTATION_FOR_TESTS, LOW, SocketTag(),
           ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
           ClientSocketPool::ProxyAuthCallback(), &proxy_pool,
@@ -1624,9 +1632,10 @@
 
   // Test socket is tagged before connected.
   uint64_t old_traffic = GetTaggedBytes(tag_val1);
-  const ClientSocketPool::GroupId kGroupId(test_server.host_port_pair(),
-                                           ClientSocketPool::SocketType::kHttp,
-                                           PrivacyMode::PRIVACY_MODE_DISABLED);
+  const ClientSocketPool::GroupId kGroupId(
+      test_server.host_port_pair(), ClientSocketPool::SocketType::kHttp,
+      PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+      false /* disable_secure_dns */);
   scoped_refptr<ClientSocketPool::SocketParams> params =
       ClientSocketPool::SocketParams::CreateForHttpForTesting();
   TestCompletionCallback callback;
@@ -1750,9 +1759,10 @@
   SocketTag tag1(SocketTag::UNSET_UID, 0x12345678);
   SocketTag tag2(getuid(), 0x87654321);
   const HostPortPair kDestination("host", 80);
-  const ClientSocketPool::GroupId kGroupId(kDestination,
-                                           ClientSocketPool::SocketType::kHttp,
-                                           PrivacyMode::PRIVACY_MODE_DISABLED);
+  const ClientSocketPool::GroupId kGroupId(
+      kDestination, ClientSocketPool::SocketType::kHttp,
+      PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+      false /* disable_secure_dns */);
   scoped_refptr<ClientSocketPool::SocketParams> socks_params =
       base::MakeRefCounted<ClientSocketPool::SocketParams>(
           nullptr /* ssl_config_for_origin */,
@@ -1843,9 +1853,10 @@
   SocketTag tag1(SocketTag::UNSET_UID, tag_val1);
   int32_t tag_val2 = 0x87654321;
   SocketTag tag2(getuid(), tag_val2);
-  const ClientSocketPool::GroupId kGroupId(test_server.host_port_pair(),
-                                           ClientSocketPool::SocketType::kSsl,
-                                           PrivacyMode::PRIVACY_MODE_DISABLED);
+  const ClientSocketPool::GroupId kGroupId(
+      test_server.host_port_pair(), ClientSocketPool::SocketType::kSsl,
+      PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+      false /* disable_secure_dns */);
 
   scoped_refptr<ClientSocketPool::SocketParams> socket_params =
       base::MakeRefCounted<ClientSocketPool::SocketParams>(
@@ -1913,9 +1924,10 @@
   SocketTag tag1(SocketTag::UNSET_UID, tag_val1);
   int32_t tag_val2 = 0x87654321;
   SocketTag tag2(getuid(), tag_val2);
-  const ClientSocketPool::GroupId kGroupId(test_server.host_port_pair(),
-                                           ClientSocketPool::SocketType::kSsl,
-                                           PrivacyMode::PRIVACY_MODE_DISABLED);
+  const ClientSocketPool::GroupId kGroupId(
+      test_server.host_port_pair(), ClientSocketPool::SocketType::kSsl,
+      PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+      false /* disable_secure_dns */);
   scoped_refptr<ClientSocketPool::SocketParams> socket_params =
       base::MakeRefCounted<ClientSocketPool::SocketParams>(
           std::make_unique<SSLConfig>() /* ssl_config_for_origin */,
@@ -1976,9 +1988,10 @@
   SocketTag tag1(SocketTag::UNSET_UID, tag_val1);
   int32_t tag_val2 = 0x87654321;
   SocketTag tag2(getuid(), tag_val2);
-  const ClientSocketPool::GroupId kGroupId(test_server.host_port_pair(),
-                                           ClientSocketPool::SocketType::kSsl,
-                                           PrivacyMode::PRIVACY_MODE_DISABLED);
+  const ClientSocketPool::GroupId kGroupId(
+      test_server.host_port_pair(), ClientSocketPool::SocketType::kSsl,
+      PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+      false /* disable_secure_dns */);
   scoped_refptr<ClientSocketPool::SocketParams> socket_params =
       base::MakeRefCounted<ClientSocketPool::SocketParams>(
           std::make_unique<SSLConfig>() /* ssl_config_for_origin */,
@@ -2055,9 +2068,10 @@
   tagging_client_socket_factory_.AddSocketDataProvider(&socket_data);
 
   const HostPortPair kDestination("www.google.com", 80);
-  const ClientSocketPool::GroupId kGroupId(kDestination,
-                                           ClientSocketPool::SocketType::kHttp,
-                                           PrivacyMode::PRIVACY_MODE_DISABLED);
+  const ClientSocketPool::GroupId kGroupId(
+      kDestination, ClientSocketPool::SocketType::kHttp,
+      PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+      false /* disable_secure_dns */);
   scoped_refptr<ClientSocketPool::SocketParams> socket_params =
       base::MakeRefCounted<ClientSocketPool::SocketParams>(
           nullptr /* ssl_config_for_origin */,
@@ -2127,9 +2141,10 @@
   tagging_client_socket_factory_.AddSSLSocketDataProvider(&ssl_data);
 
   const HostPortPair kDestination("www.google.com", 443);
-  const ClientSocketPool::GroupId kGroupId(kDestination,
-                                           ClientSocketPool::SocketType::kSsl,
-                                           PrivacyMode::PRIVACY_MODE_DISABLED);
+  const ClientSocketPool::GroupId kGroupId(
+      kDestination, ClientSocketPool::SocketType::kSsl,
+      PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+      false /* disable_secure_dns */);
 
   scoped_refptr<ClientSocketPool::SocketParams> socket_params =
       base::MakeRefCounted<ClientSocketPool::SocketParams>(
@@ -2246,9 +2261,10 @@
       ClientSocketHandle connection;
       TestCompletionCallback callback;
       int rv = connection.Init(
-          ClientSocketPool::GroupId(kHostPortPair1,
-                                    ClientSocketPool::SocketType::kHttp,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+          ClientSocketPool::GroupId(
+              kHostPortPair1, ClientSocketPool::SocketType::kHttp,
+              PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+              false /* disable_secure_dns */),
           ClientSocketPool::SocketParams::CreateForHttpForTesting(),
           base::nullopt /* proxy_annotation_tag */, MEDIUM, SocketTag(),
           ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
@@ -2294,9 +2310,10 @@
       ClientSocketHandle connection;
       TestCompletionCallback callback;
       int rv = connection.Init(
-          ClientSocketPool::GroupId(kHostPortPair2,
-                                    ClientSocketPool::SocketType::kHttp,
-                                    PrivacyMode::PRIVACY_MODE_DISABLED),
+          ClientSocketPool::GroupId(
+              kHostPortPair2, ClientSocketPool::SocketType::kHttp,
+              PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+              false /* disable_secure_dns */),
           socket_params, base::nullopt /* proxy_annotation_tag */, MEDIUM,
           SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
           callback.callback(), ClientSocketPool::ProxyAuthCallback(),
diff --git a/net/socket/websocket_transport_client_socket_pool_unittest.cc b/net/socket/websocket_transport_client_socket_pool_unittest.cc
index 8db8ca0b..fc2c62e 100644
--- a/net/socket/websocket_transport_client_socket_pool_unittest.cc
+++ b/net/socket/websocket_transport_client_socket_pool_unittest.cc
@@ -65,7 +65,9 @@
   WebSocketTransportClientSocketPoolTest()
       : group_id_(HostPortPair("www.google.com", 80),
                   ClientSocketPool::SocketType::kHttp,
-                  PrivacyMode::PRIVACY_MODE_DISABLED),
+                  PrivacyMode::PRIVACY_MODE_DISABLED,
+                  NetworkIsolationKey(),
+                  false /* disable_secure_dns */),
         params_(ClientSocketPool::SocketParams::CreateForHttpForTesting()),
         host_resolver_(new MockHostResolver),
         client_socket_factory_(&net_log_),
@@ -185,9 +187,10 @@
   ClientSocketHandle handle;
   EXPECT_EQ(
       ERR_IO_PENDING,
-      handle.Init(ClientSocketPool::GroupId(host_port_pair,
-                                            ClientSocketPool::SocketType::kHttp,
-                                            PRIVACY_MODE_DISABLED),
+      handle.Init(ClientSocketPool::GroupId(
+                      host_port_pair, ClientSocketPool::SocketType::kHttp,
+                      PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+                      false /* disable_secure_dns */),
                   ClientSocketPool::SocketParams::CreateForHttpForTesting(),
                   base::nullopt /* proxy_annotation_tag */, kDefaultPriority,
                   SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
diff --git a/net/spdy/bidirectional_stream_spdy_impl_unittest.cc b/net/spdy/bidirectional_stream_spdy_impl_unittest.cc
index f4e607b..bddadca3 100644
--- a/net/spdy/bidirectional_stream_spdy_impl_unittest.cc
+++ b/net/spdy/bidirectional_stream_spdy_impl_unittest.cc
@@ -249,7 +249,9 @@
              ProxyServer::Direct(),
              PRIVACY_MODE_DISABLED,
              SpdySessionKey::IsProxySession::kFalse,
-             SocketTag()),
+             SocketTag(),
+             NetworkIsolationKey(),
+             false /* disable_secure_dns */),
         ssl_data_(SSLSocketDataProvider(ASYNC, OK)) {
     ssl_data_.next_proto = kProtoHTTP2;
     ssl_data_.ssl_info.cert =
diff --git a/net/spdy/http2_push_promise_index_test.cc b/net/spdy/http2_push_promise_index_test.cc
index 4f505ed..6ec6578 100644
--- a/net/spdy/http2_push_promise_index_test.cc
+++ b/net/spdy/http2_push_promise_index_test.cc
@@ -61,12 +61,16 @@
               ProxyServer::Direct(),
               PRIVACY_MODE_ENABLED,
               SpdySessionKey::IsProxySession::kFalse,
-              SocketTag()),
+              SocketTag(),
+              NetworkIsolationKey(),
+              false /* disable_secure_dns */),
         key2_(HostPortPair::FromURL(url2_),
               ProxyServer::Direct(),
               PRIVACY_MODE_ENABLED,
               SpdySessionKey::IsProxySession::kFalse,
-              SocketTag()) {}
+              SocketTag(),
+              NetworkIsolationKey(),
+              false /* disable_secure_dns */) {}
 
   const GURL url1_;
   const GURL url2_;
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc
index 4be986cb..ac44b86 100644
--- a/net/spdy/spdy_http_stream_unittest.cc
+++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -132,7 +132,9 @@
              ProxyServer::Direct(),
              PRIVACY_MODE_DISABLED,
              SpdySessionKey::IsProxySession::kFalse,
-             SocketTag()),
+             SocketTag(),
+             NetworkIsolationKey(),
+             false /* disable_secure_dns */),
         ssl_(SYNCHRONOUS, OK) {
     session_deps_.net_log = &net_log_;
   }
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index 31ace14..efbeb04 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -407,7 +407,8 @@
     // all closed and not leaked at this point.
     SpdySessionKey key(HostPortPair::FromURL(request_.url),
                        ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                       SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                       SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                       NetworkIsolationKey(), false /* disable_secure_dns */);
     HttpNetworkSession* session = helper.session();
     base::WeakPtr<SpdySession> spdy_session =
         session->spdy_session_pool()->FindAvailableSession(
@@ -749,7 +750,8 @@
   // HEADERS frame, so the second transaction could not get ahead of it.
   SpdySessionKey key(HostPortPair("www.example.org", 443),
                      ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
   auto spdy_session = CreateSpdySession(helper.session(), key, log_);
   EXPECT_TRUE(spdy_session);
 
@@ -3666,7 +3668,8 @@
   SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
   SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session =
       spdy_session_pool->FindAvailableSession(
           key, /* enable_ip_based_pooling = */ true,
@@ -3781,7 +3784,8 @@
   SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
   SpdySessionKey key1(HostPortPair::FromURL(GURL(kUrl1)), ProxyServer::Direct(),
                       PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session1 =
       spdy_session_pool->FindAvailableSession(
           key1, /* enable_ip_based_pooling = */ true,
@@ -3793,7 +3797,8 @@
   // because the IP address does not match.
   SpdySessionKey key2(HostPortPair::FromURL(GURL(kUrl2)), ProxyServer::Direct(),
                       PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   EXPECT_FALSE(spdy_session_pool->FindAvailableSession(
       key2, /* enable_ip_based_pooling = */ true,
       /* is_websocket = */ false, log_));
@@ -3879,7 +3884,8 @@
   SpdySessionKey key1(HostPortPair("www.example.org", 443),
                       ProxyServer::FromPacString(kPacString),
                       PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> session1 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
           key1, true /* enable_up_base_pooling */, false /* is_websocket */,
@@ -3937,10 +3943,10 @@
   EXPECT_EQ("hello!", response_data);
 
   // Inspect the new session.
-  SpdySessionKey key2(HostPortPair("example.test", 443),
-                      ProxyServer::FromPacString(kPacString),
-                      PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+  SpdySessionKey key2(
+      HostPortPair("example.test", 443), ProxyServer::FromPacString(kPacString),
+      PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
+      SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> session2 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
           key2, true /* enable_up_base_pooling */, false /* is_websocket */,
@@ -3982,7 +3988,8 @@
   // A new SPDY session should have been created.
   SpdySessionKey key1(HostPortPair("www.example.org", 443),
                       ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
       key1, true /* enable_up_base_pooling */, false /* is_websocket */,
       NetLogWithSource()));
@@ -4028,7 +4035,8 @@
   helper.session_deps()->host_resolver->ResolveOnlyRequestNow();
   SpdySessionKey key2(HostPortPair("example.test", 443), ProxyServer::Direct(),
                       PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> session1 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
           key2, true /* enable_up_base_pooling */, false /* is_websocket */,
@@ -4136,7 +4144,8 @@
   // A new SPDY session should have been created.
   SpdySessionKey key1(HostPortPair("www.example.org", 443),
                       ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
       key1, true /* enable_up_base_pooling */, false /* is_websocket */,
       NetLogWithSource()));
@@ -4182,14 +4191,16 @@
   helper.session_deps()->host_resolver->ResolveNow(2);
   SpdySessionKey key2(HostPortPair("example.test", 443), ProxyServer::Direct(),
                       PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, kSocketTag2);
+                      SpdySessionKey::IsProxySession::kFalse, kSocketTag2,
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
 
   // Complete the third requests's DNS lookup now, which should hijack the
   // SpdySession from the second request.
   helper.session_deps()->host_resolver->ResolveNow(3);
   SpdySessionKey key3(HostPortPair("example.test", 443), ProxyServer::Direct(),
                       PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, kSocketTag3);
+                      SpdySessionKey::IsProxySession::kFalse, kSocketTag3,
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
 
   // Wait for the second request to get headers.  It should create a new H2
   // session to do so.
@@ -5235,7 +5246,8 @@
   SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
   SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session =
       spdy_session_pool->FindAvailableSession(
           key, /* enable_ip_based_pooling = */ true,
@@ -5853,13 +5865,14 @@
   // Check that the SpdySession is still in the SpdySessionPool.
   SpdySessionKey session_pool_key_direct(
       host_port_pair_, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+      NetworkIsolationKey(), false /* disable_secure_dns */);
   EXPECT_TRUE(HasSpdySession(spdy_session_pool, session_pool_key_direct));
   SpdySessionKey session_pool_key_proxy(
       host_port_pair_,
       ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP),
       PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
-      SocketTag());
+      SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
   EXPECT_FALSE(HasSpdySession(spdy_session_pool, session_pool_key_proxy));
 
   // New SpdyTestUtil instance for the session that will be used for the
@@ -6568,7 +6581,8 @@
   SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
   SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session =
       spdy_session_pool->FindAvailableSession(
           key, /* enable_ip_based_pooling = */ true,
@@ -6771,7 +6785,8 @@
   HostPortPair host_port_pair0("mail.example.org", 443);
   SpdySessionKey key0(host_port_pair0, ProxyServer::Direct(),
                       PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session0 =
       spdy_session_pool->FindAvailableSession(
           key0, /* enable_ip_based_pooling = */ true,
@@ -6782,7 +6797,8 @@
   HostPortPair host_port_pair1("docs.example.org", 443);
   SpdySessionKey key1(host_port_pair1, ProxyServer::Direct(),
                       PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session1 =
       spdy_session_pool->FindAvailableSession(
           key1, /* enable_ip_based_pooling = */ true,
@@ -8337,7 +8353,8 @@
   // Get a SpdySession.
   SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
   HttpNetworkSession* session = helper.session();
   base::WeakPtr<SpdySession> spdy_session =
       session->spdy_session_pool()->FindAvailableSession(
@@ -8456,7 +8473,8 @@
 
   SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session =
       helper.session()->spdy_session_pool()->FindAvailableSession(
           key, /* enable_ip_based_pooling = */ true,
@@ -8603,7 +8621,8 @@
 
   SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
 
   base::WeakPtr<SpdySession> spdy_session =
       helper.session()->spdy_session_pool()->FindAvailableSession(
@@ -8683,7 +8702,8 @@
 
   SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session =
       helper.session()->spdy_session_pool()->FindAvailableSession(
           key, /* enable_ip_based_pooling = */ true,
@@ -8879,7 +8899,7 @@
       HostPortPair::FromURL(request_.url),
       ProxyServer::FromURI("https://proxy:70", ProxyServer::SCHEME_HTTPS),
       PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
-      SocketTag());
+      SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
 
   base::WeakPtr<SpdySession> spdy_session =
       helper.session()->spdy_session_pool()->FindAvailableSession(
@@ -8991,7 +9011,8 @@
 
   SpdySessionKey key1(HostPortPair::FromURL(request_.url),
                       ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session1 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
           key1, /* enable_ip_based_pooling = */ true,
@@ -9005,7 +9026,8 @@
 
   SpdySessionKey key2(HostPortPair::FromURL(request2.url),
                       ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session2 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
           key1, /* enable_ip_based_pooling = */ true,
@@ -9143,7 +9165,8 @@
 
   SpdySessionKey key1(HostPortPair::FromURL(request_.url),
                       ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session1 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
           key1, /* enable_ip_based_pooling = */ true,
@@ -9158,7 +9181,8 @@
 
   SpdySessionKey key2(HostPortPair::FromURL(request2.url),
                       ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session2 =
       helper.session()->spdy_session_pool()->FindAvailableSession(
           key1, /* enable_ip_based_pooling = */ true,
@@ -9305,7 +9329,8 @@
 
   SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> spdy_session =
       helper.session()->spdy_session_pool()->FindAvailableSession(
           key, /* enable_ip_based_pooling = */ true,
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc
index a2e75a6..837256a 100644
--- a/net/spdy/spdy_proxy_client_socket_unittest.cc
+++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -217,7 +217,9 @@
                                  proxy_,
                                  PRIVACY_MODE_DISABLED,
                                  SpdySessionKey::IsProxySession::kFalse,
-                                 SocketTag()),
+                                 SocketTag(),
+                                 NetworkIsolationKey(),
+                                 false /* disable_secure_dns */),
       ssl_(SYNCHRONOUS, OK) {
   session_deps_.net_log = net_log_.bound().net_log();
 }
diff --git a/net/spdy/spdy_session_fuzzer.cc b/net/spdy/spdy_session_fuzzer.cc
index 7015731..550c88dc 100644
--- a/net/spdy/spdy_session_fuzzer.cc
+++ b/net/spdy/spdy_session_fuzzer.cc
@@ -122,7 +122,8 @@
   net::SpdySessionKey session_key(net::HostPortPair("127.0.0.1", 80),
                                   direct_connect, net::PRIVACY_MODE_DISABLED,
                                   net::SpdySessionKey::IsProxySession::kFalse,
-                                  net::SocketTag());
+                                  net::SocketTag(), net::NetworkIsolationKey(),
+                                  false /* disable_secure_dns */);
   base::WeakPtr<net::SpdySession> spdy_session(net::CreateSpdySession(
       http_session.get(), session_key, bound_test_net_log.bound()));
 
diff --git a/net/spdy/spdy_session_key.h b/net/spdy/spdy_session_key.h
index d31e3df..f8ebf248 100644
--- a/net/spdy/spdy_session_key.h
+++ b/net/spdy/spdy_session_key.h
@@ -28,16 +28,13 @@
   };
   SpdySessionKey();
 
-  // TODO(mmenke): Remove default |network_isolation_key| value (only used by
-  // tests).
-  SpdySessionKey(
-      const HostPortPair& host_port_pair,
-      const ProxyServer& proxy_server,
-      PrivacyMode privacy_mode,
-      IsProxySession is_proxy_session,
-      const SocketTag& socket_tag,
-      const NetworkIsolationKey& network_isolation_key = NetworkIsolationKey(),
-      bool disable_secure_dns = false);
+  SpdySessionKey(const HostPortPair& host_port_pair,
+                 const ProxyServer& proxy_server,
+                 PrivacyMode privacy_mode,
+                 IsProxySession is_proxy_session,
+                 const SocketTag& socket_tag,
+                 const NetworkIsolationKey& network_isolation_key,
+                 bool disable_secure_dns);
 
   SpdySessionKey(const SpdySessionKey& other);
 
diff --git a/net/spdy/spdy_session_pool_unittest.cc b/net/spdy/spdy_session_pool_unittest.cc
index 593e50f0..d478557 100644
--- a/net/spdy/spdy_session_pool_unittest.cc
+++ b/net/spdy/spdy_session_pool_unittest.cc
@@ -207,7 +207,8 @@
   HostPortPair test_host_port_pair(kTestHost, kTestPort);
   SpdySessionKey test_key = SpdySessionKey(
       test_host_port_pair, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+      NetworkIsolationKey(), false /* disable_secure_dns */);
 
   MockConnect connect_data(SYNCHRONOUS, OK);
   MockRead reads[] = {
@@ -267,7 +268,8 @@
   HostPortPair test_host_port_pair1(HostPortPair::FromURL(url1));
   SpdySessionKey key1(test_host_port_pair1, ProxyServer::Direct(),
                       PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> session1 =
       CreateSpdySession(http_session_.get(), key1, NetLogWithSource());
   base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
@@ -281,7 +283,8 @@
   HostPortPair test_host_port_pair2(HostPortPair::FromURL(url2));
   SpdySessionKey key2(test_host_port_pair2, ProxyServer::Direct(),
                       PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> session2 =
       CreateSpdySession(http_session_.get(), key2, NetLogWithSource());
   base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
@@ -296,7 +299,8 @@
   HostPortPair test_host_port_pair3(HostPortPair::FromURL(url3));
   SpdySessionKey key3(test_host_port_pair3, ProxyServer::Direct(),
                       PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> session3 =
       CreateSpdySession(http_session_.get(), key3, NetLogWithSource());
   base::WeakPtr<SpdyStream> spdy_stream3 = CreateStreamSynchronously(
@@ -373,7 +377,8 @@
   HostPortPair test_host_port_pair(kTestHost, kTestPort);
   SpdySessionKey test_key = SpdySessionKey(
       test_host_port_pair, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+      NetworkIsolationKey(), false /* disable_secure_dns */);
 
   MockConnect connect_data(SYNCHRONOUS, OK);
   MockRead reads[] = {
@@ -440,10 +445,10 @@
     session_deps_.host_resolver->rules()->AddIPLiteralRule(
         test_hosts[i].name, test_hosts[i].iplist, std::string());
 
-    test_hosts[i].key =
-        SpdySessionKey(HostPortPair(test_hosts[i].name, kTestPort),
-                       ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                       SpdySessionKey::IsProxySession::kFalse, SocketTag());
+    test_hosts[i].key = SpdySessionKey(
+        HostPortPair(test_hosts[i].name, kTestPort), ProxyServer::Direct(),
+        PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
+        SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
   }
 
   MockConnect connect_data(SYNCHRONOUS, OK);
@@ -488,7 +493,7 @@
       test_hosts[1].key.host_port_pair(),
       ProxyServer::FromPacString("HTTP http://proxy.foo.com/"),
       PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
-      SocketTag());
+      SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
   EXPECT_FALSE(TryCreateAliasedSpdySession(spdy_session_pool_, proxy_key,
                                            test_hosts[1].iplist));
 
@@ -624,10 +629,10 @@
         test_hosts[i].name, test_hosts[i].iplist, std::string());
 
     // Setup a SpdySessionKey
-    test_hosts[i].key =
-        SpdySessionKey(HostPortPair(test_hosts[i].name, kTestPort),
-                       ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                       SpdySessionKey::IsProxySession::kFalse, SocketTag());
+    test_hosts[i].key = SpdySessionKey(
+        HostPortPair(test_hosts[i].name, kTestPort), ProxyServer::Direct(),
+        PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
+        SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
   }
 
   MockRead reads[] = {
@@ -680,10 +685,10 @@
     session_deps_.host_resolver->rules()->AddIPLiteralRule(
         test_hosts[i].name, test_hosts[i].iplist, std::string());
 
-    test_hosts[i].key =
-        SpdySessionKey(HostPortPair(test_hosts[i].name, kTestPort),
-                       ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                       SpdySessionKey::IsProxySession::kFalse, SocketTag());
+    test_hosts[i].key = SpdySessionKey(
+        HostPortPair(test_hosts[i].name, kTestPort), ProxyServer::Direct(),
+        PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
+        SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
   }
 
   MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
@@ -746,10 +751,10 @@
     session_deps_.host_resolver->rules()->AddIPLiteralRule(
         test_hosts[i].name, test_hosts[i].iplist, std::string());
 
-    test_hosts[i].key =
-        SpdySessionKey(HostPortPair(test_hosts[i].name, kTestPort),
-                       ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                       SpdySessionKey::IsProxySession::kFalse, SocketTag());
+    test_hosts[i].key = SpdySessionKey(
+        HostPortPair(test_hosts[i].name, kTestPort), ProxyServer::Direct(),
+        PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
+        SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
   }
 
   MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
@@ -842,7 +847,8 @@
   HostPortPair test_host_port_pairA(kTestHostA, 80);
   SpdySessionKey keyA(test_host_port_pairA, ProxyServer::Direct(),
                       PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> sessionA =
       CreateSpdySession(http_session_.get(), keyA, NetLogWithSource());
 
@@ -873,7 +879,8 @@
   HostPortPair test_host_port_pairB(kTestHostB, 80);
   SpdySessionKey keyB(test_host_port_pairB, ProxyServer::Direct(),
                       PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> sessionB =
       CreateSpdySession(http_session_.get(), keyB, NetLogWithSource());
   EXPECT_TRUE(sessionB->IsAvailable());
@@ -895,7 +902,8 @@
   HostPortPair test_host_port_pairC(kTestHostC, 80);
   SpdySessionKey keyC(test_host_port_pairC, ProxyServer::Direct(),
                       PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> sessionC =
       CreateSpdySession(http_session_.get(), keyC, NetLogWithSource());
 
@@ -954,7 +962,8 @@
   const GURL url(kDefaultUrl);
   SpdySessionKey key(HostPortPair::FromURL(url), ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> session =
       CreateSpdySession(http_session_.get(), key, NetLogWithSource());
 
@@ -1011,7 +1020,8 @@
   const GURL url(kDefaultUrl);
   SpdySessionKey key(HostPortPair::FromURL(url), ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> session =
       CreateSpdySession(http_session_.get(), key, NetLogWithSource());
 
@@ -1059,7 +1069,8 @@
 TEST_P(SpdySessionMemoryDumpTest, DumpMemoryStats) {
   SpdySessionKey key(HostPortPair("www.example.org", 443),
                      ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                     SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                     SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                     NetworkIsolationKey(), false /* disable_secure_dns */);
 
   MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
   StaticSocketDataProvider data(reads, base::span<MockWrite>());
@@ -1121,10 +1132,10 @@
     session_deps_.host_resolver->rules()->AddIPLiteralRule(
         test_hosts[i].name, test_hosts[i].iplist, std::string());
 
-    test_hosts[i].key =
-        SpdySessionKey(HostPortPair(test_hosts[i].name, kTestPort),
-                       ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                       SpdySessionKey::IsProxySession::kFalse, SocketTag());
+    test_hosts[i].key = SpdySessionKey(
+        HostPortPair(test_hosts[i].name, kTestPort), ProxyServer::Direct(),
+        PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
+        SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
   }
 
   SpdyTestUtil spdy_util;
@@ -1278,10 +1289,10 @@
 };
 
 TEST_F(SpdySessionPoolTest, RequestSessionWithNoSessions) {
-  const SpdySessionKey kSessionKey(HostPortPair("foo.test", 443),
-                                   ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                                   SpdySessionKey::IsProxySession::kFalse,
-                                   SocketTag());
+  const SpdySessionKey kSessionKey(
+      HostPortPair("foo.test", 443), ProxyServer::Direct(),
+      PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
+      SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
 
   CreateNetworkSession();
 
@@ -1340,10 +1351,10 @@
 }
 
 TEST_F(SpdySessionPoolTest, RequestSessionDuringNotification) {
-  const SpdySessionKey kSessionKey(HostPortPair("foo.test", 443),
-                                   ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                                   SpdySessionKey::IsProxySession::kFalse,
-                                   SocketTag());
+  const SpdySessionKey kSessionKey(
+      HostPortPair("foo.test", 443), ProxyServer::Direct(),
+      PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
+      SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
 
   CreateNetworkSession();
 
@@ -1472,7 +1483,7 @@
         HostPortPair::FromURL(GURL(kSSLServerTests[i].url)),
         ProxyServer::FromPacString(kSSLServerTests[i].proxy_pac_string),
         PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
-        SocketTag());
+        SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
     sessions.push_back(
         CreateSpdySession(http_session_.get(), key, NetLogWithSource()));
   }
@@ -1527,7 +1538,7 @@
         HostPortPair::FromURL(GURL(kSSLServerTests[i].url)),
         ProxyServer::FromPacString(kSSLServerTests[i].proxy_pac_string),
         PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
-        SocketTag());
+        SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
     sessions.push_back(
         CreateSpdySession(http_session_.get(), key, NetLogWithSource()));
     streams.push_back(CreateStreamSynchronously(
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index 72568185..fc085590 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -167,7 +167,9 @@
              ProxyServer::Direct(),
              PRIVACY_MODE_DISABLED,
              SpdySessionKey::IsProxySession::kFalse,
-             SocketTag()),
+             SocketTag(),
+             NetworkIsolationKey(),
+             false /* disable_secure_dns */),
         ssl_(SYNCHRONOUS, OK) {}
 
   ~SpdySessionTest() override {
@@ -3529,9 +3531,10 @@
   auto connection2 = std::make_unique<ClientSocketHandle>();
   EXPECT_EQ(ERR_IO_PENDING,
             connection2->Init(
-                ClientSocketPool::GroupId(host_port2,
-                                          ClientSocketPool::SocketType::kHttp,
-                                          PrivacyMode::PRIVACY_MODE_DISABLED),
+                ClientSocketPool::GroupId(
+                    host_port2, ClientSocketPool::SocketType::kHttp,
+                    PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+                    false /* disable_secure_dns */),
                 ClientSocketPool::SocketParams::CreateForHttpForTesting(),
                 base::nullopt /* proxy_annotation_tag */, DEFAULT_PRIORITY,
                 SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
@@ -3575,7 +3578,8 @@
   // Create an idle SPDY session.
   SpdySessionKey key1(HostPortPair("www.example.org", 80),
                       ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   base::WeakPtr<SpdySession> session1 =
       ::net::CreateSpdySession(http_session_.get(), key1, NetLogWithSource());
   EXPECT_FALSE(pool->IsStalled());
@@ -3583,7 +3587,8 @@
   // Set up an alias for the idle SPDY session, increasing its ref count to 2.
   SpdySessionKey key2(HostPortPair("mail.example.org", 80),
                       ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                      NetworkIsolationKey(), false /* disable_secure_dns */);
   std::unique_ptr<SpdySessionPool::SpdySessionRequest> request;
   bool is_blocking_request_for_session = false;
   SpdySessionRequestDelegate request_delegate;
@@ -3616,9 +3621,10 @@
   auto connection3 = std::make_unique<ClientSocketHandle>();
   EXPECT_EQ(ERR_IO_PENDING,
             connection3->Init(
-                ClientSocketPool::GroupId(host_port3,
-                                          ClientSocketPool::SocketType::kHttp,
-                                          PrivacyMode::PRIVACY_MODE_DISABLED),
+                ClientSocketPool::GroupId(
+                    host_port3, ClientSocketPool::SocketType::kHttp,
+                    PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+                    false /* disable_secure_dns */),
                 ClientSocketPool::SocketParams::CreateForHttpForTesting(),
                 base::nullopt /* proxy_annotation_tag */, DEFAULT_PRIORITY,
                 SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
@@ -3696,9 +3702,10 @@
   auto connection2 = std::make_unique<ClientSocketHandle>();
   EXPECT_EQ(ERR_IO_PENDING,
             connection2->Init(
-                ClientSocketPool::GroupId(host_port2,
-                                          ClientSocketPool::SocketType::kHttp,
-                                          PrivacyMode::PRIVACY_MODE_DISABLED),
+                ClientSocketPool::GroupId(
+                    host_port2, ClientSocketPool::SocketType::kHttp,
+                    PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+                    false /* disable_secure_dns */),
                 ClientSocketPool::SocketParams::CreateForHttpForTesting(),
                 base::nullopt /* proxy_annotation_tag */, DEFAULT_PRIORITY,
                 SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
@@ -3730,10 +3737,12 @@
   HostPortPair host_port_pair("www.example.org", 443);
   SpdySessionKey key_privacy_enabled(
       host_port_pair, ProxyServer::Direct(), PRIVACY_MODE_ENABLED,
-      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+      NetworkIsolationKey(), false /* disable_secure_dns */);
   SpdySessionKey key_privacy_disabled(
       host_port_pair, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-      SpdySessionKey::IsProxySession::kFalse, SocketTag());
+      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+      NetworkIsolationKey(), false /* disable_secure_dns */);
 
   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_enabled));
   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_privacy_disabled));
@@ -6494,7 +6503,7 @@
   key_ = SpdySessionKey(HostPortPair::FromURL(test_url_), ProxyServer::Direct(),
                         PRIVACY_MODE_DISABLED,
                         SpdySessionKey::IsProxySession::kFalse, SocketTag(),
-                        kNetworkIsolationKey1);
+                        kNetworkIsolationKey1, false /* disable_secure_dns */);
 
   spdy::SpdyAltSvcIR altsvc_ir(/* stream_id = */ 1);
   altsvc_ir.add_altsvc(alternative_service_);
diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc
index 87fbacc..e2620f00 100644
--- a/net/spdy/spdy_stream_unittest.cc
+++ b/net/spdy/spdy_stream_unittest.cc
@@ -80,7 +80,8 @@
   base::WeakPtr<SpdySession> CreateDefaultSpdySession() {
     SpdySessionKey key(HostPortPair::FromURL(url_), ProxyServer::Direct(),
                        PRIVACY_MODE_DISABLED,
-                       SpdySessionKey::IsProxySession::kFalse, SocketTag());
+                       SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+                       NetworkIsolationKey(), false /* disable_secure_dns */);
     return CreateSpdySession(session_.get(), key, NetLogWithSource());
   }
 
@@ -343,9 +344,10 @@
 
   data.RunUntilPaused();
 
-  const SpdySessionKey key(HostPortPair::FromURL(url_), ProxyServer::Direct(),
-                           PRIVACY_MODE_DISABLED,
-                           SpdySessionKey::IsProxySession::kFalse, SocketTag());
+  const SpdySessionKey key(
+      HostPortPair::FromURL(url_), ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
+      SpdySessionKey::IsProxySession::kFalse, SocketTag(),
+      NetworkIsolationKey(), false /* disable_secure_dns */);
   const GURL pushed_url(kPushUrl);
   HttpRequestInfo push_request;
   push_request.url = pushed_url;
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index 9c9633a1..2bb9b46 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -501,7 +501,8 @@
   int rv = connection->Init(
       ClientSocketPool::GroupId(key.host_port_pair(),
                                 ClientSocketPool::SocketType::kSsl,
-                                key.privacy_mode()),
+                                key.privacy_mode(), NetworkIsolationKey(),
+                                false /* disable_secure_dns */),
       socket_params, base::nullopt /* proxy_annotation_tag */, MEDIUM,
       key.socket_tag(), ClientSocketPool::RespectLimits::ENABLED,
       callback.callback(), ClientSocketPool::ProxyAuthCallback(),
diff --git a/net/url_request/http_with_dns_over_https_unittest.cc b/net/url_request/http_with_dns_over_https_unittest.cc
index 0376a00..e0ea11b6 100644
--- a/net/url_request/http_with_dns_over_https_unittest.cc
+++ b/net/url_request/http_with_dns_over_https_unittest.cc
@@ -230,7 +230,8 @@
 
   ClientSocketPool::GroupId group_id(
       HostPortPair(request_info.url.host(), request_info.url.IntPort()),
-      ClientSocketPool::SocketType::kHttp, PrivacyMode::PRIVACY_MODE_DISABLED);
+      ClientSocketPool::SocketType::kHttp, PrivacyMode::PRIVACY_MODE_DISABLED,
+      NetworkIsolationKey(), false /* disable_secure_dns */);
   EXPECT_EQ(network_session
                 ->GetSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL,
                                 ProxyServer::Direct())
diff --git a/net/websockets/websocket_basic_stream_adapters_test.cc b/net/websockets/websocket_basic_stream_adapters_test.cc
index 8f287de..a7be454 100644
--- a/net/websockets/websocket_basic_stream_adapters_test.cc
+++ b/net/websockets/websocket_basic_stream_adapters_test.cc
@@ -68,9 +68,10 @@
             nullptr /* ssl_config_for_proxy */);
     TestCompletionCallback callback;
     int rv = connection->Init(
-        ClientSocketPool::GroupId(host_port_pair_,
-                                  ClientSocketPool::SocketType::kSsl,
-                                  PrivacyMode::PRIVACY_MODE_DISABLED),
+        ClientSocketPool::GroupId(
+            host_port_pair_, ClientSocketPool::SocketType::kSsl,
+            PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+            false /* disable_secure_dns */),
         socks_params, TRAFFIC_ANNOTATION_FOR_TESTS /* proxy_annotation_tag */,
         MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
         callback.callback(), ClientSocketPool::ProxyAuthCallback(),
@@ -285,7 +286,9 @@
              ProxyServer::Direct(),
              PRIVACY_MODE_DISABLED,
              SpdySessionKey::IsProxySession::kFalse,
-             SocketTag()),
+             SocketTag(),
+             NetworkIsolationKey(),
+             false /* disable_secure_dns */),
         session_(SpdySessionDependencies::SpdyCreateSession(&session_deps_)),
         ssl_(SYNCHRONOUS, OK) {}
 
diff --git a/net/websockets/websocket_basic_stream_test.cc b/net/websockets/websocket_basic_stream_test.cc
index 95c2c44f..335c786 100644
--- a/net/websockets/websocket_basic_stream_test.cc
+++ b/net/websockets/websocket_basic_stream_test.cc
@@ -143,9 +143,10 @@
 
     auto transport_socket = std::make_unique<ClientSocketHandle>();
     scoped_refptr<ClientSocketPool::SocketParams> null_params;
-    ClientSocketPool::GroupId group_id(HostPortPair("a", 80),
-                                       ClientSocketPool::SocketType::kHttp,
-                                       PrivacyMode::PRIVACY_MODE_DISABLED);
+    ClientSocketPool::GroupId group_id(
+        HostPortPair("a", 80), ClientSocketPool::SocketType::kHttp,
+        PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+        false /* disable_secure_dns */);
     transport_socket->Init(
         group_id, null_params, base::nullopt /* proxy_annotation_tag */, MEDIUM,
         SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
diff --git a/net/websockets/websocket_handshake_stream_create_helper_test.cc b/net/websockets/websocket_handshake_stream_create_helper_test.cc
index ce3702a..9ab35ee2 100644
--- a/net/websockets/websocket_handshake_stream_create_helper_test.cc
+++ b/net/websockets/websocket_handshake_stream_create_helper_test.cc
@@ -90,9 +90,10 @@
     socket_factory_maker_.SetExpectations(expect_written, return_to_read);
     auto socket_handle = std::make_unique<ClientSocketHandle>();
     socket_handle->Init(
-        ClientSocketPool::GroupId(HostPortPair("a", 80),
-                                  ClientSocketPool::SocketType::kHttp,
-                                  PrivacyMode::PRIVACY_MODE_DISABLED),
+        ClientSocketPool::GroupId(
+            HostPortPair("a", 80), ClientSocketPool::SocketType::kHttp,
+            PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
+            false /* disable_secure_dns */),
         scoped_refptr<ClientSocketPool::SocketParams>(),
         base::nullopt /* proxy_annotation_tag */, MEDIUM, SocketTag(),
         ClientSocketPool::RespectLimits::ENABLED, CompletionOnceCallback(),
@@ -255,10 +256,10 @@
 
         std::unique_ptr<HttpNetworkSession> http_network_session =
             SpdySessionDependencies::SpdyCreateSession(&session_deps);
-        const SpdySessionKey key(HostPortPair::FromURL(url),
-                                 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-                                 SpdySessionKey::IsProxySession::kFalse,
-                                 SocketTag());
+        const SpdySessionKey key(
+            HostPortPair::FromURL(url), ProxyServer::Direct(),
+            PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
+            SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
         base::WeakPtr<SpdySession> spdy_session =
             CreateSpdySession(http_network_session.get(), key, net_log);
         std::unique_ptr<WebSocketHandshakeStreamBase> handshake =
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc
index d7efd7f..ef965d6 100644
--- a/pdf/out_of_process_instance.cc
+++ b/pdf/out_of_process_instance.cc
@@ -995,7 +995,7 @@
   viewport_info.scroll.y =
       -top_toolbar_height_in_viewport_coords_ * device_scale_;
   viewport_info.offset = available_area_.point();
-  viewport_info.zoom = zoom_ * device_scale_;
+  viewport_info.zoom_device_scale_factor = zoom_ * device_scale_;
 
   engine_->GetSelection(&viewport_info.selection_start_page_index,
                         &viewport_info.selection_start_char_index,
diff --git a/ppapi/c/private/ppb_pdf.h b/ppapi/c/private/ppb_pdf.h
index 0f1a15d..4a36698 100644
--- a/ppapi/c/private/ppb_pdf.h
+++ b/ppapi/c/private/ppb_pdf.h
@@ -34,7 +34,7 @@
 };
 
 struct PP_PrivateAccessibilityViewportInfo {
-  double zoom;
+  double zoom_device_scale_factor;
   struct PP_Point scroll;
   struct PP_Point offset;
   uint32_t selection_start_page_index;
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index 3f6cca0..40bd6c2 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -255,7 +255,7 @@
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(PP_PrivateAccessibilityViewportInfo)
-  IPC_STRUCT_TRAITS_MEMBER(zoom)
+  IPC_STRUCT_TRAITS_MEMBER(zoom_device_scale_factor)
   IPC_STRUCT_TRAITS_MEMBER(scroll)
   IPC_STRUCT_TRAITS_MEMBER(offset)
   IPC_STRUCT_TRAITS_MEMBER(selection_start_page_index)
diff --git a/services/media_session/audio_focus_request.cc b/services/media_session/audio_focus_request.cc
index 65ec389..a304a722 100644
--- a/services/media_session/audio_focus_request.cc
+++ b/services/media_session/audio_focus_request.cc
@@ -30,7 +30,7 @@
   // Listen for mojo errors.
   receiver_.set_disconnect_handler(base::BindOnce(
       &AudioFocusRequest::OnConnectionError, base::Unretained(this)));
-  session_.set_connection_error_handler(base::BindOnce(
+  session_.set_disconnect_handler(base::BindOnce(
       &AudioFocusRequest::OnConnectionError, base::Unretained(this)));
 }
 
diff --git a/services/media_session/audio_focus_request.h b/services/media_session/audio_focus_request.h
index 72895e7..091246e6 100644
--- a/services/media_session/audio_focus_request.h
+++ b/services/media_session/audio_focus_request.h
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/media_session/public/mojom/audio_focus.mojom.h"
 #include "services/media_session/public/mojom/media_controller.mojom.h"
 
@@ -94,7 +95,7 @@
 
   std::unique_ptr<MediaController> controller_;
 
-  mojom::MediaSessionPtr session_;
+  mojo::Remote<mojom::MediaSession> session_;
   mojom::MediaSessionInfoPtr session_info_;
   mojom::AudioFocusType audio_focus_type_;
 
diff --git a/services/media_session/media_controller.cc b/services/media_session/media_controller.cc
index 80160c51..82780f0 100644
--- a/services/media_session/media_controller.cc
+++ b/services/media_session/media_controller.cc
@@ -32,7 +32,7 @@
         observer_(std::move(observer)) {
     // Set a connection error handler so that we will remove observers that have
     // had an error / been closed.
-    observer_.set_connection_error_handler(base::BindOnce(
+    observer_.set_disconnect_handler(base::BindOnce(
         &MediaController::CleanupImageObservers, base::Unretained(owner_)));
 
     // Flush the observer with the latest state.
@@ -41,7 +41,7 @@
 
   ~ImageObserverHolder() = default;
 
-  bool is_valid() const { return !observer_.encountered_error(); }
+  bool is_valid() const { return observer_.is_connected(); }
 
   mojom::MediaSessionImageType type() const { return type_; }
 
@@ -81,7 +81,7 @@
 
   int const desired_size_px_;
 
-  mojom::MediaControllerImageObserverPtr observer_;
+  mojo::Remote<mojom::MediaControllerImageObserver> observer_;
 
   base::WeakPtrFactory<ImageObserverHolder> weak_ptr_factory_{this};
 
diff --git a/services/network/dns_config_change_manager.cc b/services/network/dns_config_change_manager.cc
index 497dc2d..b79c640 100644
--- a/services/network/dns_config_change_manager.cc
+++ b/services/network/dns_config_change_manager.cc
@@ -22,14 +22,13 @@
 }
 
 void DnsConfigChangeManager::RequestNotifications(
-    mojom::DnsConfigChangeManagerClientPtr client) {
-  clients_.AddPtr(std::move(client));
+    mojo::PendingRemote<mojom::DnsConfigChangeManagerClient> client) {
+  clients_.Add(std::move(client));
 }
 
 void DnsConfigChangeManager::OnDNSChanged() {
-  clients_.ForAllPtrs([](mojom::DnsConfigChangeManagerClient* client) {
+  for (const auto& client : clients_)
     client->OnSystemDnsConfigChanged();
-  });
 }
 
 void DnsConfigChangeManager::OnInitialDNSConfigRead() {
diff --git a/services/network/dns_config_change_manager.h b/services/network/dns_config_change_manager.h
index 058d5bb..0d072c4 100644
--- a/services/network/dns_config_change_manager.h
+++ b/services/network/dns_config_change_manager.h
@@ -10,8 +10,9 @@
 
 #include "base/component_export.h"
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
 #include "net/base/network_change_notifier.h"
 #include "services/network/public/mojom/host_resolver.mojom.h"
 
@@ -29,7 +30,7 @@
 
   // mojom::DnsConfigChangeManager implementation:
   void RequestNotifications(
-      mojom::DnsConfigChangeManagerClientPtr client) override;
+      mojo::PendingRemote<mojom::DnsConfigChangeManagerClient> client) override;
 
  private:
   // net::NetworkChangeNotifier::DNSObserver implementation:
@@ -37,7 +38,7 @@
   void OnInitialDNSConfigRead() override;
 
   mojo::ReceiverSet<mojom::DnsConfigChangeManager> receivers_;
-  mojo::InterfacePtrSet<mojom::DnsConfigChangeManagerClient> clients_;
+  mojo::RemoteSet<mojom::DnsConfigChangeManagerClient> clients_;
 
   DISALLOW_COPY_AND_ASSIGN(DnsConfigChangeManager);
 };
diff --git a/services/network/dns_config_change_manager_unittest.cc b/services/network/dns_config_change_manager_unittest.cc
index 03e587d..f32295f 100644
--- a/services/network/dns_config_change_manager_unittest.cc
+++ b/services/network/dns_config_change_manager_unittest.cc
@@ -9,7 +9,7 @@
 
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace network {
@@ -21,13 +21,7 @@
   explicit TestDnsConfigChangeManagerClient(DnsConfigChangeManager* manager) {
     mojo::Remote<mojom::DnsConfigChangeManager> manager_remote;
     manager->AddReceiver(manager_remote.BindNewPipeAndPassReceiver());
-
-    mojom::DnsConfigChangeManagerClientPtr client_ptr;
-    mojom::DnsConfigChangeManagerClientRequest client_request(
-        mojo::MakeRequest(&client_ptr));
-    binding_.Bind(std::move(client_request));
-
-    manager_remote->RequestNotifications(std::move(client_ptr));
+    manager_remote->RequestNotifications(receiver_.BindNewPipeAndPassRemote());
   }
 
   void OnSystemDnsConfigChanged() override {
@@ -48,7 +42,7 @@
   int num_notifications_ = 0;
   int num_notifications_expected_ = INT_MAX;
   base::RunLoop run_loop_;
-  mojo::Binding<mojom::DnsConfigChangeManagerClient> binding_{this};
+  mojo::Receiver<mojom::DnsConfigChangeManagerClient> receiver_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TestDnsConfigChangeManagerClient);
 };
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 9d0cbc5e..d5ac13f 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -1706,12 +1706,12 @@
   builder.set_ssl_config_service(std::move(ssl_config_service));
 
   if (!params_->initial_proxy_config &&
-      !params_->proxy_config_client_request.is_pending()) {
+      !params_->proxy_config_client_receiver.is_valid()) {
     params_->initial_proxy_config =
         net::ProxyConfigWithAnnotation::CreateDirect();
   }
   builder.set_proxy_config_service(std::make_unique<ProxyConfigServiceMojo>(
-      std::move(params_->proxy_config_client_request),
+      std::move(params_->proxy_config_client_receiver),
       std::move(params_->initial_proxy_config),
       std::move(params_->proxy_config_poller_client)));
   builder.set_pac_quick_check_enabled(params_->pac_quick_check_enabled);
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index c9483b31..c7d482e 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -2167,9 +2167,9 @@
     mojom::NetworkContextParamsPtr context_params = CreateContextParams();
     context_params->initial_proxy_config = net::ProxyConfigWithAnnotation(
         initial_proxy_config_set.proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS);
-    mojom::ProxyConfigClientPtr config_client;
-    context_params->proxy_config_client_request =
-        mojo::MakeRequest(&config_client);
+    mojo::Remote<mojom::ProxyConfigClient> config_client;
+    context_params->proxy_config_client_receiver =
+        config_client.BindNewPipeAndPassReceiver();
     std::unique_ptr<NetworkContext> network_context =
         CreateContextWithParams(std::move(context_params));
 
@@ -2252,9 +2252,9 @@
 TEST_F(NetworkContextTest, NoInitialProxyConfig) {
   mojom::NetworkContextParamsPtr context_params = CreateContextParams();
   context_params->initial_proxy_config.reset();
-  mojom::ProxyConfigClientPtr config_client;
-  context_params->proxy_config_client_request =
-      mojo::MakeRequest(&config_client);
+  mojo::Remote<mojom::ProxyConfigClient> config_client;
+  context_params->proxy_config_client_receiver =
+      config_client.BindNewPipeAndPassReceiver();
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(std::move(context_params));
 
@@ -2300,9 +2300,9 @@
   // Create a NetworkContext without an initial proxy configuration.
   mojom::NetworkContextParamsPtr context_params = CreateContextParams();
   context_params->initial_proxy_config.reset();
-  mojom::ProxyConfigClientPtr config_client;
-  context_params->proxy_config_client_request =
-      mojo::MakeRequest(&config_client);
+  mojo::Remote<mojom::ProxyConfigClient> config_client;
+  context_params->proxy_config_client_receiver =
+      config_client.BindNewPipeAndPassReceiver();
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(std::move(context_params));
 
@@ -2326,9 +2326,9 @@
   // Create a NetworkContext without an initial proxy configuration.
   mojom::NetworkContextParamsPtr context_params = CreateContextParams();
   context_params->initial_proxy_config.reset();
-  mojom::ProxyConfigClientPtr config_client;
-  context_params->proxy_config_client_request =
-      mojo::MakeRequest(&config_client);
+  mojo::Remote<mojom::ProxyConfigClient> config_client;
+  context_params->proxy_config_client_receiver =
+      config_client.BindNewPipeAndPassReceiver();
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(std::move(context_params));
 
@@ -3625,12 +3625,14 @@
 
   net::ClientSocketPool::GroupId group_id1(
       test_server.host_port_pair(), net::ClientSocketPool::SocketType::kHttp,
-      net::PrivacyMode::PRIVACY_MODE_ENABLED, kKey1);
+      net::PrivacyMode::PRIVACY_MODE_ENABLED, kKey1,
+      false /* disable_secure_dns */);
   EXPECT_EQ(
       1, GetSocketCountForGroup(network_context.get(), group_id1.ToString()));
   net::ClientSocketPool::GroupId group_id2(
       test_server.host_port_pair(), net::ClientSocketPool::SocketType::kHttp,
-      net::PrivacyMode::PRIVACY_MODE_ENABLED, kKey2);
+      net::PrivacyMode::PRIVACY_MODE_ENABLED, kKey2,
+      false /* disable_secure_dns */);
   EXPECT_EQ(
       2, GetSocketCountForGroup(network_context.get(), group_id2.ToString()));
 }
@@ -4472,9 +4474,9 @@
     mojom::NetworkContextParamsPtr context_params = CreateContextParams();
     context_params->initial_proxy_config = net::ProxyConfigWithAnnotation(
         proxy_data.proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS);
-    mojom::ProxyConfigClientPtr config_client;
-    context_params->proxy_config_client_request =
-        mojo::MakeRequest(&config_client);
+    mojo::Remote<mojom::ProxyConfigClient> config_client;
+    context_params->proxy_config_client_receiver =
+        config_client.BindNewPipeAndPassReceiver();
     std::unique_ptr<NetworkContext> network_context =
         CreateContextWithParams(std::move(context_params));
 
diff --git a/services/network/proxy_config_service_mojo.cc b/services/network/proxy_config_service_mojo.cc
index 11191b80..b2a281b 100644
--- a/services/network/proxy_config_service_mojo.cc
+++ b/services/network/proxy_config_service_mojo.cc
@@ -9,19 +9,19 @@
 namespace network {
 
 ProxyConfigServiceMojo::ProxyConfigServiceMojo(
-    mojom::ProxyConfigClientRequest proxy_config_client_request,
+    mojo::PendingReceiver<mojom::ProxyConfigClient>
+        proxy_config_client_receiver,
     base::Optional<net::ProxyConfigWithAnnotation> initial_proxy_config,
-    mojom::ProxyConfigPollerClientPtrInfo proxy_poller_client)
-    : binding_(this) {
-  DCHECK(initial_proxy_config || proxy_config_client_request.is_pending());
+    mojom::ProxyConfigPollerClientPtrInfo proxy_poller_client) {
+  DCHECK(initial_proxy_config || proxy_config_client_receiver.is_valid());
 
   if (initial_proxy_config)
     OnProxyConfigUpdated(*initial_proxy_config);
 
-  if (proxy_config_client_request.is_pending()) {
-    binding_.Bind(std::move(proxy_config_client_request));
+  if (proxy_config_client_receiver.is_valid()) {
+    receiver_.Bind(std::move(proxy_config_client_receiver));
     // Only use the |proxy_poller_client| if there's a
-    // |proxy_config_client_request|.
+    // |proxy_config_client_receiver|.
     proxy_poller_client_.Bind(std::move(proxy_poller_client));
   }
 }
diff --git a/services/network/proxy_config_service_mojo.h b/services/network/proxy_config_service_mojo.h
index 0a63cc88..55265287 100644
--- a/services/network/proxy_config_service_mojo.h
+++ b/services/network/proxy_config_service_mojo.h
@@ -9,7 +9,8 @@
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/optional.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "net/proxy_resolution/proxy_config.h"
 #include "net/proxy_resolution/proxy_config_service.h"
 #include "net/proxy_resolution/proxy_config_with_annotation.h"
@@ -27,15 +28,16 @@
     : public net::ProxyConfigService,
       public mojom::ProxyConfigClient {
  public:
-  // |proxy_config_client_request| is the Mojo pipe over which new
+  // |proxy_config_client_receiver| is the Mojo pipe over which new
   // configurations are received. |initial_proxy_config| is the initial proxy
-  // configuration. If nullptr, waits for the initial configuration over
-  // |proxy_config_client_request|. Either |proxy_config_client_request| or
-  // |initial_proxy_config| must be non-null. If |proxy_config_client_request|
-  // and |proxy_poller_client| are non-null, calls into |proxy_poller_client|
-  // whenever OnLazyPoll() is invoked.
+  // configuration. If mojo::NullReceiver(), waits for the initial configuration
+  // over |proxy_config_client_receiver|. Either |proxy_config_client_receiver|
+  // or |initial_proxy_config| must be non-null. If
+  // |proxy_config_client_receiver| and |proxy_poller_client| are non-null,
+  // calls into |proxy_poller_client| whenever OnLazyPoll() is invoked.
   explicit ProxyConfigServiceMojo(
-      mojom::ProxyConfigClientRequest proxy_config_client_request,
+      mojo::PendingReceiver<mojom::ProxyConfigClient>
+          proxy_config_client_receiver,
       base::Optional<net::ProxyConfigWithAnnotation> initial_proxy_config,
       mojom::ProxyConfigPollerClientPtrInfo proxy_poller_client);
   ~ProxyConfigServiceMojo() override;
@@ -58,7 +60,7 @@
   net::ProxyConfigWithAnnotation config_;
   bool config_pending_ = true;
 
-  mojo::Binding<mojom::ProxyConfigClient> binding_;
+  mojo::Receiver<mojom::ProxyConfigClient> receiver_{this};
 
   base::ObserverList<Observer>::Unchecked observers_;
 
diff --git a/services/network/proxy_config_service_mojo_unittest.cc b/services/network/proxy_config_service_mojo_unittest.cc
index b8bed6e..6a9c56a 100644
--- a/services/network/proxy_config_service_mojo_unittest.cc
+++ b/services/network/proxy_config_service_mojo_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/macros.h"
 #include "base/test/task_environment.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/proxy_resolution/proxy_config.h"
 #include "net/proxy_resolution/proxy_config_service.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
@@ -69,7 +70,7 @@
  public:
   ProxyConfigServiceMojoTest()
       : task_environment_(base::test::TaskEnvironment::MainThreadType::IO),
-        proxy_config_service_(mojo::MakeRequest(&config_client_),
+        proxy_config_service_(config_client_.BindNewPipeAndPassReceiver(),
                               base::Optional<net::ProxyConfigWithAnnotation>(),
                               nullptr),
         observer_(&proxy_config_service_) {
@@ -86,7 +87,7 @@
   void WaitForConfig() { task_environment_.RunUntilIdle(); }
 
   base::test::TaskEnvironment task_environment_;
-  mojom::ProxyConfigClientPtr config_client_;
+  mojo::Remote<mojom::ProxyConfigClient> config_client_;
   ProxyConfigServiceMojo proxy_config_service_;
   TestProxyConfigServiceObserver observer_;
 
diff --git a/services/network/public/mojom/host_resolver.mojom b/services/network/public/mojom/host_resolver.mojom
index e4683719..7114773f 100644
--- a/services/network/public/mojom/host_resolver.mojom
+++ b/services/network/public/mojom/host_resolver.mojom
@@ -301,5 +301,5 @@
 // An interface that broadcasts DNS config change events.
 interface DnsConfigChangeManager {
   // Requests to receive notification when there is a DNS config change.
-  RequestNotifications(DnsConfigChangeManagerClient client_ptr);
+  RequestNotifications(pending_remote<DnsConfigChangeManagerClient> client);
 };
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 7bbb8e0..712f621 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -274,7 +274,7 @@
   //
   // If both are null, the NetworkContext will not use a proxy.
   ProxyConfigWithAnnotation? initial_proxy_config;
-  ProxyConfigClient&? proxy_config_client_request;
+  pending_receiver<ProxyConfigClient>? proxy_config_client_receiver;
 
   // If |custom_proxy_config_client_receiver| is set, this context will listen
   // for updates to the custom proxy config, and use it if applicable for
diff --git a/services/tracing/perfetto/privacy_filtered_fields-inl.h b/services/tracing/perfetto/privacy_filtered_fields-inl.h
index ad0ee3b..b3f15621 100644
--- a/services/tracing/perfetto/privacy_filtered_fields-inl.h
+++ b/services/tracing/perfetto/privacy_filtered_fields-inl.h
@@ -137,11 +137,12 @@
 constexpr int kStreamingProfilePacketIndices[] = {1, 2, -1};
 constexpr MessageInfo kStreamingProfilePacket = {kStreamingProfilePacketIndices,
                                                  nullptr};
-// EDIT: Contains field numbers: {3, 8} which are not autogenerated.
+
+// EDIT: Contains field numbers: {3, 8, 58} which are not autogenerated.
 
 // Proto Message: TracePacket
-constexpr int kTracePacketIndices[] = {3,  8,  10, 11, 12, 35, 36,
-                                       41, 42, 43, 44, 51, 54, -1};
+constexpr int kTracePacketIndices[] = {3,  8,  10, 11, 12, 35, 36, 41,
+                                       42, 43, 44, 51, 54, 58, -1};
 constexpr MessageInfo const* kTracePacketComplexMessages[] = {
     nullptr,
     nullptr,
@@ -155,7 +156,8 @@
     &kProcessDescriptor,
     &kThreadDescriptor,
     &kChromeMetadataPacket,
-    &kStreamingProfilePacket};
+    &kStreamingProfilePacket,
+    nullptr};
 constexpr MessageInfo kTracePacket = {kTracePacketIndices,
                                       kTracePacketComplexMessages};
 
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
index 3a6f0cd9..7a0bd07 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
@@ -47,6 +47,7 @@
 #include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_writer.h"
 #include "third_party/perfetto/protos/perfetto/trace/chrome/chrome_metadata.pbzero.h"
 #include "third_party/perfetto/protos/perfetto/trace/chrome/chrome_trace_event.pbzero.h"
+#include "third_party/perfetto/protos/perfetto/trace/clock_snapshot.pbzero.h"
 #include "third_party/perfetto/protos/perfetto/trace/trace_packet.pbzero.h"
 #include "third_party/perfetto/protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
 
@@ -101,6 +102,19 @@
 #endif  // defined(OS_ANDROID) && defined(OFFICIAL_BUILD)
 }
 
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
+// Linux, Android, and Fuchsia all use CLOCK_MONOTONIC. See crbug.com/166153
+// about efforts to unify base::TimeTicks across all platforms.
+constexpr perfetto::protos::pbzero::ClockSnapshot::Clock::BuiltinClocks
+    kTraceClockId = perfetto::protos::pbzero::ClockSnapshot::Clock::MONOTONIC;
+#else
+// Mac and Windows TimeTicks advance when sleeping, so are closest to BOOTTIME
+// in behavior.
+// TODO(eseckler): Support specifying Mac/Win platform clocks in BuiltinClocks.
+constexpr perfetto::protos::pbzero::ClockSnapshot::Clock::BuiltinClocks
+    kTraceClockId = perfetto::protos::pbzero::ClockSnapshot::Clock::BOOTTIME;
+#endif
+
 }  // namespace
 
 using perfetto::protos::pbzero::ChromeEventBundle;
@@ -175,6 +189,7 @@
   }
   trace_packet->set_timestamp(
       TRACE_TIME_TICKS_NOW().since_origin().InNanoseconds());
+  trace_packet->set_timestamp_clock_id(kTraceClockId);
   auto* chrome_metadata = trace_packet->set_chrome_metadata();
   generator.Run(chrome_metadata, privacy_filtering_enabled_);
 }
@@ -194,6 +209,7 @@
     }
     trace_packet->set_timestamp(
         TRACE_TIME_TICKS_NOW().since_origin().InNanoseconds());
+    trace_packet->set_timestamp_clock_id(kTraceClockId);
     event_bundle = trace_packet->set_chrome_events();
   }
 
@@ -267,6 +283,7 @@
 
   trace_packet->set_timestamp(
       TRACE_TIME_TICKS_NOW().since_origin().InNanoseconds());
+  trace_packet->set_timestamp_clock_id(kTraceClockId);
   auto* chrome_metadata = trace_packet->set_chrome_metadata();
   for (auto& generator : *proto_generators) {
     generator.Run(chrome_metadata, privacy_filtering_enabled_);
@@ -276,8 +293,6 @@
     return;
   }
 
-  trace_packet->set_timestamp(
-      TRACE_TIME_TICKS_NOW().since_origin().InNanoseconds());
   ChromeEventBundle* event_bundle = trace_packet->set_chrome_events();
 
   for (auto& generator : *json_generators) {
@@ -955,6 +970,7 @@
   trace_packet->set_incremental_state_cleared(true);
   trace_packet->set_timestamp(
       TRACE_TIME_TICKS_NOW().since_origin().InNanoseconds());
+  trace_packet->set_timestamp_clock_id(kTraceClockId);
   auto process_type = GetProcessType(TraceLog::GetInstance()->process_name());
   ProcessDescriptor* process_desc = trace_packet->set_process_descriptor();
   process_desc->set_pid(process_id_);
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 4b8d563d..6ebcb87 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -478,7 +478,10 @@
             ],
             "experiments": [
                 {
-                    "name": "Enabled",
+                    "name": "EnabledWithSafetyStory",
+                    "params": {
+                        "story": "safety"
+                    },
                     "enable_features": [
                         "PasswordManagerOnboardingAndroid"
                     ]
@@ -1431,6 +1434,22 @@
             ]
         }
     ],
+    "BoostThreadPriorityOnLibraryLoadingAndBackgroundMode": [
+        {
+            "platforms": [
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "BoostPriorityAndBackgroundThreadMode",
+                    "enable_features": [
+                        "BoostThreadPriorityOnLibraryLoading",
+                        "WindowsThreadModeBackground"
+                    ]
+                }
+            ]
+        }
+    ],
     "BrowserBlacklist": [
         {
             "platforms": [
diff --git a/third_party/README.chromium b/third_party/README.chromium
index d19364d..c809883b 100644
--- a/third_party/README.chromium
+++ b/third_party/README.chromium
@@ -1,14 +1,4 @@
 The third_party directory contains sources from other projects.
 
-Code in third_party must document the license under which the source is being
-used. If the source itself does not include a license header or file, create
-an entry in this file that refers to reliable documentation of the project's
-license terms on the web (and add a note pointing here in the README file in
-that directory).
-
-When adding a new directory, or updating a directory to a version which has
-a different license from before, please add chromium-third-party@google.com
-as a reviewer on the change.
-
-<Include table of license information here, once it is available>
-
+For guidelines on adding a new package to the third_party directory
+can be found at [docs/adding_to_third_party.md](docs/adding_to_third_party.md)
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index d50e06f..9e8287d9 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -333,7 +333,6 @@
     "platform/web_scrollbar_buttons_placement.h",
     "platform/web_scrollbar_overlay_color_theme.h",
     "platform/web_security_origin.h",
-    "platform/web_security_style.h",
     "platform/web_set_sink_id_callbacks.h",
     "platform/web_size.h",
     "platform/web_source_buffer.h",
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn
index 36b95844..2a0450038 100644
--- a/third_party/blink/public/common/BUILD.gn
+++ b/third_party/blink/public/common/BUILD.gn
@@ -122,6 +122,7 @@
     "scheduler/web_scheduler_tracked_feature.h",
     "screen_orientation/web_screen_orientation_lock_type.h",
     "screen_orientation/web_screen_orientation_type.h",
+    "security/security_style.h",
     "service_worker/service_worker_status_code.h",
     "service_worker/service_worker_type_converters.h",
     "service_worker/service_worker_types.h",
diff --git a/third_party/blink/public/common/security/security_style.h b/third_party/blink/public/common/security/security_style.h
new file mode 100644
index 0000000..efcf4c9
--- /dev/null
+++ b/third_party/blink/public/common/security/security_style.h
@@ -0,0 +1,17 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_SECURITY_SECURITY_STYLE_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_SECURITY_SECURITY_STYLE_H_
+namespace blink {
+// This enum represents the security state of a resource.
+enum class SecurityStyle {
+  kUnknown,
+  kNeutral,
+  kInsecure,
+  kSecure,
+  kLast = kSecure
+};
+}  // namespace blink
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_SECURITY_SECURITY_STYLE_H_"
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
index 2e0a8fae..326a4141 100644
--- a/third_party/blink/public/platform/web_runtime_features.h
+++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -158,7 +158,6 @@
   BLINK_PLATFORM_EXPORT static void EnablePushMessaging(bool);
   BLINK_PLATFORM_EXPORT static void EnableReducedReferrerGranularity(bool);
   BLINK_PLATFORM_EXPORT static void EnableRemotePlaybackAPI(bool);
-  BLINK_PLATFORM_EXPORT static void EnableResourceLoadScheduler(bool);
   BLINK_PLATFORM_EXPORT static void
   EnableRestrictAutomaticLazyFrameLoadingToDataSaver(bool);
   BLINK_PLATFORM_EXPORT static void
diff --git a/third_party/blink/public/platform/web_security_style.h b/third_party/blink/public/platform/web_security_style.h
deleted file mode 100644
index 3a60a1a..0000000
--- a/third_party/blink/public/platform/web_security_style.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_SECURITY_STYLE_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_SECURITY_STYLE_H_
-namespace blink {
-// This enum represents the security state of a resource.
-enum WebSecurityStyle {
-  kWebSecurityStyleUnknown,
-  kWebSecurityStyleNeutral,
-  kWebSecurityStyleInsecure,
-  kWebSecurityStyleSecure,
-  kWebSecurityStyleLast = kWebSecurityStyleSecure
-};
-}  // namespace blink
-#endif
diff --git a/third_party/blink/public/platform/web_url_response.h b/third_party/blink/public/platform/web_url_response.h
index 0c0e3683..500fa6e 100644
--- a/third_party/blink/public/platform/web_url_response.h
+++ b/third_party/blink/public/platform/web_url_response.h
@@ -37,8 +37,8 @@
 #include "base/time/time.h"
 #include "net/cert/ct_policy_status.h"
 #include "net/http/http_response_info.h"
+#include "third_party/blink/public/common/security/security_style.h"
 #include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_security_style.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_vector.h"
 
@@ -217,7 +217,7 @@
   BLINK_PLATFORM_EXPORT void SetCTPolicyCompliance(net::ct::CTPolicyCompliance);
   BLINK_PLATFORM_EXPORT void SetIsLegacyTLSVersion(bool);
 
-  BLINK_PLATFORM_EXPORT void SetSecurityStyle(WebSecurityStyle);
+  BLINK_PLATFORM_EXPORT void SetSecurityStyle(SecurityStyle);
 
   BLINK_PLATFORM_EXPORT void SetSecurityDetails(const WebSecurityDetails&);
   BLINK_PLATFORM_EXPORT base::Optional<WebSecurityDetails>
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc
index 099c6f1..44e37c6 100644
--- a/third_party/blink/renderer/core/animation/animation.cc
+++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -408,8 +408,6 @@
 
 // https://drafts.csswg.org/web-animations/#the-current-time-of-an-animation
 double Animation::currentTime() {
-  PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand);
-
   // 1. If the animation’s hold time is resolved,
   //    The current time is the animation’s hold time.
   if (hold_time_.has_value())
@@ -439,17 +437,7 @@
 }
 
 double Animation::CurrentTimeInternal() const {
-  double result = hold_time_.value_or(CalculateCurrentTime());
-#if DCHECK_IS_ON()
-  // We can't enforce this check during Unset due to other assertions.
-  if (internal_play_state_ != kUnset) {
-    const_cast<Animation*>(this)->UpdateCurrentTimingState(
-        kTimingUpdateOnDemand);
-    double hold_or_current_time = hold_time_.value_or(CalculateCurrentTime());
-    DCHECK(AreEqualOrNull(result, hold_or_current_time));
-  }
-#endif
-  return result;
+  return hold_time_.value_or(CalculateCurrentTime());
 }
 
 double Animation::UnlimitedCurrentTimeInternal() const {
@@ -465,9 +453,6 @@
     int compositor_group,
     const PaintArtifactCompositor* paint_artifact_compositor,
     bool start_on_compositor) {
-  PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand,
-                                    kDoNotSetCompositorPending);
-
   bool soft_change =
       compositor_state_ &&
       (Paused() || compositor_state_->playback_rate != playback_rate_);
@@ -496,9 +481,8 @@
 
   DCHECK(!compositor_state_ || compositor_state_->start_time);
 
-  if (!should_start) {
+  if (!should_start)
     current_time_pending_ = false;
-  }
 
   if (should_start) {
     compositor_group_ = compositor_group;
@@ -517,13 +501,24 @@
     }
   }
 
+  // Apply updates if not waiting on a start time. Play pending animations that
+  // are waiting on a start time will get updated from NotifyStartTime.
+  // Finished animations may not trigger an Update call if finished in the same
+  // frame that they are started. Calling ApplyUpdates for this specific case
+  // ensures that the finished promise and event are properly triggered.
+  AnimationPlayState play_state = CalculateAnimationPlayState();
+  bool finished = play_state == kFinished;
+  if (pending_pause_ || (pending_play_ && (start_time_ || finished))) {
+    ApplyUpdates(timeline_
+                     ? timeline_->CurrentTimeSeconds().value_or(NullValue())
+                     : NullValue());
+  }
+
+  NotifyProbe();
   return true;
 }
 
 void Animation::PostCommit(double timeline_time) {
-  PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand,
-                                    kDoNotSetCompositorPending);
-
   compositor_pending_ = false;
 
   if (!compositor_state_ || compositor_state_->pending_action == kNone)
@@ -537,9 +532,6 @@
 }
 
 void Animation::NotifyCompositorStartTime(double timeline_time) {
-  PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand,
-                                    kDoNotSetCompositorPending);
-
   if (compositor_state_) {
     DCHECK_EQ(compositor_state_->pending_action, kStart);
     DCHECK(!compositor_state_->start_time);
@@ -557,7 +549,7 @@
       // Unlikely, but possible.
       // FIXME: Depending on what changed above this might still be pending.
       // Maybe...
-      current_time_pending_ = false;
+      NotifyStartTime(timeline_time);
       return;
     }
 
@@ -573,23 +565,8 @@
 }
 
 void Animation::NotifyStartTime(double timeline_time) {
-  if (Playing()) {
-    DCHECK(!start_time_);
-    DCHECK(hold_time_.has_value());
-
-    if (playback_rate_ == 0) {
-      SetStartTimeInternal(timeline_time);
-    } else {
-      SetStartTimeInternal(timeline_time +
-                           CurrentTimeInternal() / -playback_rate_);
-    }
-
-    // FIXME: This avoids marking this animation as outdated needlessly when a
-    // start time is notified, but we should refactor how outdating works to
-    // avoid this.
-    ClearOutdated();
-    current_time_pending_ = false;
-  }
+  current_time_pending_ = false;
+  ApplyUpdates(timeline_time);
 }
 
 bool Animation::Affects(const Element& element,
@@ -867,6 +844,24 @@
   SetCurrentTimeInternal(new_current_time, kTimingUpdateOnDemand);
 }
 
+void Animation::CommitPendingPause(double ready_time) {
+  internal_play_state_ = kUnset;
+
+  DCHECK(pending_pause_);
+  pending_pause_ = false;
+  if (start_time_ && !hold_time_)
+    hold_time_ = (ready_time - start_time_.value()) * playback_rate_;
+
+  ApplyPendingPlaybackRate();
+  start_time_ = base::nullopt;
+
+  // Resolve pending ready promise.
+  if (ready_promise_)
+    ResolvePromiseMaybeAsync(ready_promise_.Get());
+
+  UpdateFinishedState(UpdateType::kContinuous, NotificationType::kAsync);
+}
+
 void Animation::Unpause() {
   if (!paused_)
     return;
@@ -874,6 +869,7 @@
   PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand);
 
   current_time_pending_ = true;
+  pending_play_ = true;
   UnpauseInternal();
 }
 
@@ -881,6 +877,7 @@
   if (!paused_)
     return;
   paused_ = false;
+  pending_pause_ = false;
   SetCurrentTimeInternal(CurrentTimeInternal(), kTimingUpdateOnDemand);
 }
 
@@ -897,16 +894,13 @@
     return;
   }
 
-  if (!Playing()) {
+  if (!Playing())
     start_time_ = base::nullopt;
-  }
 
-  if (PlayStateInternal() == kIdle) {
+  if (PlayStateInternal() == kIdle)
     hold_time_ = 0;
-  }
 
   internal_play_state_ = kUnset;
-  pending_play_ = true;
   pending_pause_ = false;
   finished_ = false;
   UnpauseInternal();
@@ -920,6 +914,47 @@
     start_time_ = base::nullopt;
     SetCurrentTimeInternal(EffectEnd(), kTimingUpdateOnDemand);
   }
+  pending_play_ = !start_time_ || active_playback_rate_;
+}
+
+void Animation::CommitPendingPlay(double ready_time) {
+  DCHECK(start_time_ || hold_time_);
+  DCHECK(pending_play_);
+  pending_play_ = false;
+
+  // Update hold and start time.
+  if (timeline_ && timeline_->IsScrollTimeline()) {
+    // Special handling for scroll timelines.  The start time is always zero
+    // when the animation is playing. This forces the current time to match the
+    // timeline time. TODO(crbug.com/916117): Resolve in spec.
+    start_time_ = 0;
+    ApplyPendingPlaybackRate();
+    if (playback_rate_ != 0)
+      hold_time_ = base::nullopt;
+  } else if (hold_time_) {
+    ApplyPendingPlaybackRate();
+    if (playback_rate_ != 0) {
+      start_time_ = ready_time - hold_time_.value() / playback_rate_;
+      hold_time_ = base::nullopt;
+    } else {
+      start_time_ = ready_time;
+    }
+  } else if (start_time_ && active_playback_rate_) {
+    double current_time_to_match =
+        (ready_time - start_time_.value()) * active_playback_rate_.value();
+    ApplyPendingPlaybackRate();
+    if (playback_rate_ == 0)
+      hold_time_ = start_time_ = current_time_to_match;
+    else
+      start_time_ = ready_time - current_time_to_match / playback_rate_;
+  }
+
+  // Resolve pending ready promise.
+  if (ready_promise_)
+    ResolvePromiseMaybeAsync(ready_promise_.Get());
+
+  // Update finished state.
+  UpdateFinishedState(UpdateType::kContinuous, NotificationType::kAsync);
 }
 
 // https://drafts.csswg.org/web-animations/#reversing-an-animation-section
@@ -1105,9 +1140,42 @@
   QueueFinishedEvent();
 }
 
-void Animation::CommitAllUpdatesForTesting() {
+void Animation::ApplyUpdates(double ready_time) {
+  // Applies all updates to an animation. The state of the animation may change
+  // between the time that pending updates are triggered and when the updates
+  // are applied. Thus, flags are used instead of directly queuing callbacks
+  // to enable validation that the pending state change is still relevant.
+  // Multiple updates may be applied with the caveat that the pending play and
+  // pending pause are mutually exclusive.
+  DCHECK(!(pending_play_ && pending_pause_));
+  if (pending_play_)
+    CommitPendingPlay(ready_time);
+  else if (pending_pause_)
+    CommitPendingPause(ready_time);
+
+  ApplyPendingPlaybackRate();
+
   if (pending_finish_notification_)
     CommitFinishNotification();
+
+  DCHECK(!pending_play_);
+  DCHECK(!pending_pause_);
+  DCHECK(!pending_finish_notification_);
+  DCHECK(!active_playback_rate_);
+
+  // TODO(crbug.com/960944): Deprecate.
+  current_time_pending_ = false;
+  internal_play_state_ = CalculatePlayState();
+  animation_play_state_ = CalculateAnimationPlayState();
+
+  NotifyProbe();
+}
+
+void Animation::CommitAllUpdatesForTesting() {
+  base::Optional<double> timeline_time;
+  if (timeline_)
+    timeline_time = timeline_->CurrentTimeSeconds();
+  ApplyUpdates(timeline_time.value_or(NullValue()));
 }
 
 // https://drafts.csswg.org/web-animations/#setting-the-playback-rate-of-an-animation
@@ -1136,6 +1204,15 @@
 
   setPlaybackRate(playback_rate);
 
+  if (playback_rate == 0) {
+    pending_play_ = pending_pause_ = false;
+    if (play_state == kRunning || play_state == kFinished) {
+      double timeline_time = TimelineTime();
+      if (!IsNull(timeline_time))
+        start_time_ = timeline_time;
+    }
+  }
+
   if (pending())
     active_playback_rate_ = stored_playback_rate;
 }
@@ -1155,7 +1232,7 @@
   if (!ready_promise_) {
     ready_promise_ = MakeGarbageCollected<AnimationPromise>(
         ExecutionContext::From(script_state), this, AnimationPromise::kReady);
-    if (PlayStateInternal() != kPending)
+    if (!pending())
       ready_promise_->Resolve(this);
   }
   return ready_promise_->Promise(script_state->World());
@@ -1242,13 +1319,20 @@
   DCHECK(std::isfinite(playback_rate));
   DCHECK_NE(playback_rate, playback_rate_);
 
-  if (!Limited() && !Paused() && start_time_)
+  if (!Limited() && !Paused() && start_time_) {
     current_time_pending_ = true;
+    pending_play_ = true;
+  }
 
   double stored_current_time = CurrentTimeInternal();
-  if ((playback_rate_ < 0 && playback_rate >= 0) ||
-      (playback_rate_ > 0 && playback_rate <= 0))
+  if ((playback_rate_ < 0 && playback_rate > 0) ||
+      (playback_rate_ > 0 && playback_rate < 0)) {
     finished_ = false;
+    // Reversing the direction of a finished animation will trigger playing
+    // the animation.
+    if (Limited() && !Paused() && start_time_)
+      pending_play_ = true;
+  }
 
   playback_rate_ = playback_rate;
   start_time_ = base::nullopt;
@@ -1433,17 +1517,6 @@
   if (!timeline_)
     return false;
 
-  if (reason == kTimingUpdateForAnimationFrame) {
-    // Pending tasks are committed when the animation is 'ready'. This can be
-    // at the time of promise resolution or after a frame tick.  Whereas the
-    // spec calls for creating scheduled tasks to commit pending changes, in the
-    // Blink implementation, this is an acknowledgment that the changes have
-    // taken affect.
-    // TODO(crbug.com/960944): Consider restructuring implementation to more
-    // closely align with the recommended algorithm in the spec.
-    ResetPendingTasks();
-  }
-
   PlayStateUpdateScope update_scope(*this, reason, kDoNotSetCompositorPending);
 
   ClearOutdated();
@@ -1581,7 +1654,6 @@
   paused_ = false;
   internal_play_state_ = kIdle;
   current_time_pending_ = false;
-
   animation_play_state_ = kIdle;
 
   // Apply changes synchronously.
diff --git a/third_party/blink/renderer/core/animation/animation.h b/third_party/blink/renderer/core/animation/animation.h
index ea510e4..8e28b4a1 100644
--- a/third_party/blink/renderer/core/animation/animation.h
+++ b/third_party/blink/renderer/core/animation/animation.h
@@ -144,11 +144,12 @@
   ScriptPromise ready(ScriptState*);
 
   bool Paused() const {
-    return GetPlayState() == kPaused && !is_paused_for_testing_;
+    return CalculateAnimationPlayState() == kPaused && !is_paused_for_testing_;
   }
 
   bool Playing() const override {
-    return GetPlayState() == kRunning && !Limited() && !is_paused_for_testing_;
+    return CalculateAnimationPlayState() == kRunning && !Limited() &&
+           !is_paused_for_testing_;
   }
 
   // Indicates if the animation is out of sync with the compositor. A change to
@@ -336,6 +337,9 @@
   void ScheduleAsyncFinish();
   void AsyncFinishMicrotask();
   void CommitFinishNotification();
+  void CommitPendingPause(double ready_time);
+  void CommitPendingPlay(double ready_time);
+  void ApplyUpdates(double ready_time);
 
   // Tracking the state of animations in dev tools.
   void NotifyProbe();
diff --git a/third_party/blink/renderer/core/animation/animation_test.cc b/third_party/blink/renderer/core/animation/animation_test.cc
index eeefe3f..05a43554 100644
--- a/third_party/blink/renderer/core/animation/animation_test.cc
+++ b/third_party/blink/renderer/core/animation/animation_test.cc
@@ -167,6 +167,8 @@
   }
 
   bool SimulateFrame(double time_ms) {
+    animation->CommitAllUpdatesForTesting();
+
     last_frame_time = time_ms;
     const auto* paint_artifact_compositor =
         GetDocument().GetFrame()->View()->GetPaintArtifactCompositor();
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 7e9946f..16a8951a 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -2689,7 +2689,7 @@
       GetPage()->DeprecatedLocalMainFrame()->ContentLayoutObject();
   if (!layout_view)
     return IntSize();
-  return layout_view->DocumentRect().Size();
+  return PixelSnappedIntRect(layout_view->DocumentRect()).Size();
 }
 
 WebSize WebViewImpl::ContentsPreferredMinimumSize() {
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 33945b1d..58d776a 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -529,7 +529,8 @@
     return;
 
   DCHECK_EQ(frame_->View(), this);
-  SetLayoutOverflowSize(layout_view->DocumentRect().Size());
+  SetLayoutOverflowSize(
+      PixelSnappedIntRect(layout_view->DocumentRect()).Size());
 }
 
 void LocalFrameView::AdjustViewSizeAndLayout() {
@@ -632,8 +633,9 @@
   value->SetString(
       "frame",
       String::Format("0x%" PRIxPTR, reinterpret_cast<uintptr_t>(frame_.Get())));
-  value->SetInteger("contentsHeightAfterLayout",
-                    GetLayoutView()->DocumentRect().Height());
+  value->SetInteger(
+      "contentsHeightAfterLayout",
+      PixelSnappedIntRect(GetLayoutView()->DocumentRect()).Height());
   value->SetInteger("visibleHeight", Height());
   value->SetInteger("approximateBlankCharacterCount",
                     base::saturated_cast<int>(
@@ -648,7 +650,8 @@
 void LocalFrameView::PerformLayout(bool in_subtree_layout) {
   DCHECK(in_subtree_layout || layout_subtree_root_list_.IsEmpty());
 
-  int contents_height_before_layout = GetLayoutView()->DocumentRect().Height();
+  double contents_height_before_layout =
+      GetLayoutView()->DocumentRect().Height();
   TRACE_EVENT_BEGIN1(
       PERFORM_LAYOUT_TRACE_CATEGORIES, "LocalFrameView::performLayout",
       "contentsHeightBeforeLayout", contents_height_before_layout);
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index d997dd15e..247152a 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -631,7 +631,8 @@
   if (!GetFrameView() || !GetFrameView()->GetLayoutView())
     return WebSize();
 
-  return GetFrameView()->GetLayoutView()->DocumentRect().Size();
+  return PixelSnappedIntRect(GetFrameView()->GetLayoutView()->DocumentRect())
+      .Size();
 }
 
 bool WebLocalFrameImpl::HasVisibleContent() const {
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
index 8740093f..0e18ea2 100644
--- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -540,16 +540,16 @@
 
   String security_state = protocol::Security::SecurityStateEnum::Unknown;
   switch (response.GetSecurityStyle()) {
-    case kWebSecurityStyleUnknown:
+    case SecurityStyle::kUnknown:
       security_state = protocol::Security::SecurityStateEnum::Unknown;
       break;
-    case kWebSecurityStyleNeutral:
+    case SecurityStyle::kNeutral:
       security_state = protocol::Security::SecurityStateEnum::Neutral;
       break;
-    case kWebSecurityStyleInsecure:
+    case SecurityStyle::kInsecure:
       security_state = protocol::Security::SecurityStateEnum::Insecure;
       break;
-    case kWebSecurityStyleSecure:
+    case SecurityStyle::kSecure:
       security_state = protocol::Security::SecurityStateEnum::Secure;
       break;
   }
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc
index baa63c4..d135c40 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -1751,10 +1751,6 @@
   if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
     auto fragments = NGPaintFragment::InlineFragmentsFor(this);
     if (fragments.IsInLayoutNGInlineFormattingContext()) {
-      if (Container()->IsLayoutNGMixin() && StyleRef().HasOutline()) {
-        Container()->InvalidateDisplayItemClients(
-            PaintInvalidationReason::kOutline);
-      }
       for (NGPaintFragment* fragment : fragments) {
         paint_invalidator.InvalidateDisplayItemClient(*fragment,
                                                       invalidation_reason);
diff --git a/third_party/blink/renderer/core/layout/layout_view.cc b/third_party/blink/renderer/core/layout/layout_view.cc
index f15be07..82387ff4 100644
--- a/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/third_party/blink/renderer/core/layout/layout_view.cc
@@ -716,10 +716,8 @@
       MouseEventManager::UpdateHoverReason::kScrollOffsetChanged);
 }
 
-IntRect LayoutView::DocumentRect() const {
-  PhysicalRect overflow_rect = FlipForWritingMode(LayoutOverflowRect());
-  // TODO(crbug.com/650768): The pixel snapping looks incorrect.
-  return PixelSnappedIntRect(overflow_rect);
+PhysicalRect LayoutView::DocumentRect() const {
+  return FlipForWritingMode(LayoutOverflowRect());
 }
 
 IntSize LayoutView::GetLayoutSize(
diff --git a/third_party/blink/renderer/core/layout/layout_view.h b/third_party/blink/renderer/core/layout/layout_view.h
index 4b32f408..f37105ef 100644
--- a/third_party/blink/renderer/core/layout/layout_view.h
+++ b/third_party/blink/renderer/core/layout/layout_view.h
@@ -193,7 +193,7 @@
   PaintLayerCompositor* Compositor();
   bool UsesCompositing() const;
 
-  IntRect DocumentRect() const;
+  PhysicalRect DocumentRect() const;
 
   IntervalArena* GetIntervalArena();
 
diff --git a/third_party/blink/renderer/core/page/print_context.cc b/third_party/blink/renderer/core/page/print_context.cc
index 2c91f87..d87dad4 100644
--- a/third_party/blink/renderer/core/page/print_context.cc
+++ b/third_party/blink/renderer/core/page/print_context.cc
@@ -70,7 +70,7 @@
   }
 
   auto* view = frame_->GetDocument()->GetLayoutView();
-  const IntRect& document_rect = view->DocumentRect();
+  const PhysicalRect& document_rect = view->DocumentRect();
   FloatSize page_size = frame_->ResizePageRectsKeepingRatio(
       print_size, FloatSize(document_rect.Width(), document_rect.Height()));
   ComputePageRectsWithPageSizeInternal(page_size);
@@ -89,7 +89,7 @@
 
   auto* view = frame_->GetDocument()->GetLayoutView();
 
-  IntRect doc_rect = view->DocumentRect();
+  IntRect snapped_doc_rect = PixelSnappedIntRect(view->DocumentRect());
 
   int page_width = page_size_in_pixels.Width();
   // We scaled with floating point arithmetic and need to ensure results like
@@ -99,14 +99,15 @@
 
   bool is_horizontal = view->StyleRef().IsHorizontalWritingMode();
 
-  int doc_logical_height = is_horizontal ? doc_rect.Height() : doc_rect.Width();
+  int doc_logical_height =
+      is_horizontal ? snapped_doc_rect.Height() : snapped_doc_rect.Width();
   int page_logical_height = is_horizontal ? page_height : page_width;
   int page_logical_width = is_horizontal ? page_width : page_height;
 
-  int inline_direction_start = doc_rect.X();
-  int inline_direction_end = doc_rect.MaxX();
-  int block_direction_start = doc_rect.Y();
-  int block_direction_end = doc_rect.MaxY();
+  int inline_direction_start = snapped_doc_rect.X();
+  int inline_direction_end = snapped_doc_rect.MaxX();
+  int block_direction_start = snapped_doc_rect.Y();
+  int block_direction_end = snapped_doc_rect.MaxY();
   if (!is_horizontal) {
     std::swap(block_direction_start, inline_direction_start);
     std::swap(block_direction_end, inline_direction_end);
diff --git a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
index 4c55767..3eaac61 100644
--- a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
+++ b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
@@ -48,8 +48,8 @@
 // First Meaningful Paint.
 void FirstMeaningfulPaintDetector::MarkNextPaintAsMeaningfulIfNeeded(
     const LayoutObjectCounter& counter,
-    int contents_height_before_layout,
-    int contents_height_after_layout,
+    double contents_height_before_layout,
+    double contents_height_after_layout,
     int visible_height) {
   if (network_quiet_reached_)
     return;
@@ -60,10 +60,10 @@
   if (visible_height == 0)
     return;
 
-  double ratio_before = std::max(
-      1.0, static_cast<double>(contents_height_before_layout) / visible_height);
-  double ratio_after = std::max(
-      1.0, static_cast<double>(contents_height_after_layout) / visible_height);
+  double ratio_before =
+      std::max(1.0, contents_height_before_layout / visible_height);
+  double ratio_after =
+      std::max(1.0, contents_height_after_layout / visible_height);
   double significance = delta / ((ratio_before + ratio_after) / 2);
 
   // If the page has many blank characters, the significance value is
diff --git a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
index f717fe5..a0c9db2 100644
--- a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
+++ b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
@@ -34,8 +34,8 @@
   virtual ~FirstMeaningfulPaintDetector() = default;
 
   void MarkNextPaintAsMeaningfulIfNeeded(const LayoutObjectCounter&,
-                                         int contents_height_before_layout,
-                                         int contents_height_after_layout,
+                                         double contents_height_before_layout,
+                                         double contents_height_after_layout,
                                          int visible_height);
   void NotifyInputEvent();
   void NotifyPaint();
diff --git a/third_party/blink/renderer/core/paint/view_painter.cc b/third_party/blink/renderer/core/paint/view_painter.cc
index 9a0e96c..69ff740 100644
--- a/third_party/blink/renderer/core/paint/view_painter.cc
+++ b/third_party/blink/renderer/core/paint/view_painter.cc
@@ -45,7 +45,7 @@
     return;
 
   // The background rect always includes at least the visible content size.
-  IntRect background_rect(PixelSnappedIntRect(layout_view_.BackgroundRect()));
+  PhysicalRect background_rect(layout_view_.BackgroundRect());
 
   // When printing, paint the entire unclipped scrolling content area.
   if (paint_info.IsPrinting())
@@ -63,7 +63,7 @@
     // DocumentRect is relative to ScrollOrigin. Add ScrollOrigin to let it be
     // in the space of ContentsProperties(). See ScrollTranslation in
     // object_paint_properties.h for details.
-    document_rect.MoveBy(layout_view_.ScrollOrigin());
+    document_rect.Move(PhysicalOffset(layout_view_.ScrollOrigin()));
     background_rect.Unite(document_rect);
     background_client = &layout_view_.GetScrollableArea()
                              ->GetScrollingBackgroundDisplayItemClient();
@@ -74,12 +74,13 @@
   }
 
   if (layout_view_.HasBoxDecorationBackground()) {
-    PaintBoxDecorationBackgroundInternal(paint_info, background_rect,
-                                         *background_client);
+    PaintBoxDecorationBackgroundInternal(
+        paint_info, PixelSnappedIntRect(background_rect), *background_client);
   }
   if (has_touch_action_rect) {
     BoxPainter(layout_view_)
-        .RecordHitTestData(paint_info, PhysicalRect(background_rect),
+        .RecordHitTestData(paint_info,
+                           PhysicalRect(PixelSnappedIntRect(background_rect)),
                            *background_client);
   }
 
diff --git a/third_party/blink/renderer/modules/vr/vr_frame_data.cc b/third_party/blink/renderer/modules/vr/vr_frame_data.cc
index d3e0774..b135694 100644
--- a/third_party/blink/renderer/modules/vr/vr_frame_data.cc
+++ b/third_party/blink/renderer/modules/vr/vr_frame_data.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/modules/vr/vr_frame_data.h"
 
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
 #include "third_party/blink/renderer/modules/vr/vr_eye_parameters.h"
 #include "third_party/blink/renderer/modules/vr/vr_pose.h"
 
diff --git a/third_party/blink/renderer/modules/vr/vr_pose.cc b/third_party/blink/renderer/modules/vr/vr_pose.cc
index d5bc8c4..50d3abac 100644
--- a/third_party/blink/renderer/modules/vr/vr_pose.cc
+++ b/third_party/blink/renderer/modules/vr/vr_pose.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/blink/renderer/modules/vr/vr_pose.h"
 
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+
 namespace blink {
 
 namespace {
diff --git a/third_party/blink/renderer/modules/vr/vr_pose.h b/third_party/blink/renderer/modules/vr/vr_pose.h
index 626bf330..0e94034 100644
--- a/third_party/blink/renderer/modules/vr/vr_pose.h
+++ b/third_party/blink/renderer/modules/vr/vr_pose.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_VR_VR_POSE_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_VR_VR_POSE_H_
 
-#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
diff --git a/third_party/blink/renderer/modules/vr/vr_stage_parameters.cc b/third_party/blink/renderer/modules/vr/vr_stage_parameters.cc
index 3b2169b..3f29821 100644
--- a/third_party/blink/renderer/modules/vr/vr_stage_parameters.cc
+++ b/third_party/blink/renderer/modules/vr/vr_stage_parameters.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "third_party/blink/renderer/modules/vr/vr_stage_parameters.h"
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
 #include "third_party/blink/renderer/modules/xr/xr_utils.h"
 #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
 
diff --git a/third_party/blink/renderer/modules/vr/vr_stage_parameters.h b/third_party/blink/renderer/modules/vr/vr_stage_parameters.h
index 24e6432..f2aca2a 100644
--- a/third_party/blink/renderer/modules/vr/vr_stage_parameters.h
+++ b/third_party/blink/renderer/modules/vr/vr_stage_parameters.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_VR_VR_STAGE_PARAMETERS_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_VR_VR_STAGE_PARAMETERS_H_
 
-#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.h b/third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.h
index 86f624c..c40a504 100644
--- a/third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.h
+++ b/third_party/blink/renderer/modules/wake_lock/wake_lock_state_record.h
@@ -7,7 +7,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "services/device/public/mojom/wake_lock.mojom-blink.h"
+#include "services/device/public/mojom/wake_lock.mojom-blink-forward.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/modules/wake_lock/wake_lock_type.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.h b/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.h
index 3228e9c7..a2630eb 100644
--- a/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.h
+++ b/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.h
@@ -11,7 +11,7 @@
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
-#include "services/device/public/mojom/wake_lock.mojom-blink.h"
+#include "services/device/public/mojom/wake_lock.mojom-blink-forward.h"
 #include "third_party/blink/public/mojom/permissions/permission.mojom-blink.h"
 #include "third_party/blink/public/mojom/wake_lock/wake_lock.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_function.h"
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_encoder_base.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_encoder_base.idl
deleted file mode 100644
index f966384..0000000
--- a/third_party/blink/renderer/modules/webgpu/gpu_render_encoder_base.idl
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://gpuweb.github.io/gpuweb/
-
-[
-    RuntimeEnabled=WebGPU
-] interface mixin GPURenderEncoderBase {
-    void setPipeline(GPURenderPipeline pipeline);
-
-    void setIndexBuffer(GPUBuffer buffer, optional GPUBufferSize offset = 0);
-    void setVertexBuffer(unsigned long slot,
-                         GPUBuffer buffer,
-                         optional GPUBufferSize offset = 0);
-
-    void draw(unsigned long vertexCount, unsigned long instanceCount,
-              unsigned long firstVertex,
-              unsigned long firstInstance);
-    void drawIndexed(unsigned long indexCount, unsigned long instanceCount,
-                     unsigned long firstIndex,
-                     long baseVertex,
-                     unsigned long firstInstance);
-
-    void drawIndirect(GPUBuffer indirectBuffer,
-                      GPUBufferSize indirectOffset);
-    void drawIndexedIndirect(GPUBuffer indirectBuffer,
-                             GPUBufferSize indirectOffset);
-};
-GPURenderEncoderBase includes GPUProgrammablePassEncoder;
diff --git a/third_party/blink/renderer/modules/webmidi/DEPS b/third_party/blink/renderer/modules/webmidi/DEPS
index 9e5294b9..35e7842 100644
--- a/third_party/blink/renderer/modules/webmidi/DEPS
+++ b/third_party/blink/renderer/modules/webmidi/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
     "+media/midi/midi_service.mojom-blink.h",
+    "+media/midi/midi_service.mojom-blink-forward.h",
     "-third_party/blink/renderer/modules",
     "+third_party/blink/renderer/modules/event_modules.h",
     "+third_party/blink/renderer/modules/event_target_modules.h",
diff --git a/third_party/blink/renderer/modules/webmidi/midi_access.h b/third_party/blink/renderer/modules/webmidi/midi_access.h
index 0d81d19..73a42977 100644
--- a/third_party/blink/renderer/modules/webmidi/midi_access.h
+++ b/third_party/blink/renderer/modules/webmidi/midi_access.h
@@ -32,7 +32,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBMIDI_MIDI_ACCESS_H_
 
 #include <memory>
-#include "media/midi/midi_service.mojom-blink.h"
+#include "media/midi/midi_service.mojom-blink-forward.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
diff --git a/third_party/blink/renderer/modules/webmidi/midi_access_initializer.h b/third_party/blink/renderer/modules/webmidi/midi_access_initializer.h
index e347e49..b327188 100644
--- a/third_party/blink/renderer/modules/webmidi/midi_access_initializer.h
+++ b/third_party/blink/renderer/modules/webmidi/midi_access_initializer.h
@@ -6,10 +6,10 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBMIDI_MIDI_ACCESS_INITIALIZER_H_
 
 #include <memory>
-#include "media/midi/midi_service.mojom-blink.h"
+#include "media/midi/midi_service.mojom-blink-forward.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/permissions/permission.mojom-blink.h"
-#include "third_party/blink/public/mojom/permissions/permission_status.mojom-blink.h"
+#include "third_party/blink/public/mojom/permissions/permission_status.mojom-blink-forward.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
diff --git a/third_party/blink/renderer/modules/webmidi/midi_input.h b/third_party/blink/renderer/modules/webmidi/midi_input.h
index f09b3b0a..23d2067 100644
--- a/third_party/blink/renderer/modules/webmidi/midi_input.h
+++ b/third_party/blink/renderer/modules/webmidi/midi_input.h
@@ -31,7 +31,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBMIDI_MIDI_INPUT_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBMIDI_MIDI_INPUT_H_
 
-#include "media/midi/midi_service.mojom-blink.h"
+#include "media/midi/midi_service.mojom-blink-forward.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
 #include "third_party/blink/renderer/modules/webmidi/midi_port.h"
 
diff --git a/third_party/blink/renderer/modules/webmidi/midi_port.h b/third_party/blink/renderer/modules/webmidi/midi_port.h
index 0f62c6e6..f7c9214 100644
--- a/third_party/blink/renderer/modules/webmidi/midi_port.h
+++ b/third_party/blink/renderer/modules/webmidi/midi_port.h
@@ -31,7 +31,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBMIDI_MIDI_PORT_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBMIDI_MIDI_PORT_H_
 
-#include "media/midi/midi_service.mojom-blink.h"
+#include "media/midi/midi_service.mojom-blink-forward.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
diff --git a/third_party/blink/renderer/modules/websockets/mock_websocket_channel.h b/third_party/blink/renderer/modules/websockets/mock_websocket_channel.h
index de129bd..8e8574b5 100644
--- a/third_party/blink/renderer/modules/websockets/mock_websocket_channel.h
+++ b/third_party/blink/renderer/modules/websockets/mock_websocket_channel.h
@@ -9,7 +9,7 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/public/mojom/devtools/console_message.mojom-blink.h"
+#include "third_party/blink/public/mojom/devtools/console_message.mojom-blink-forward.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
 #include "third_party/blink/renderer/modules/websockets/websocket_channel.h"
 #include "third_party/blink/renderer/platform/blob/blob_data.h"
diff --git a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
index c69b7536..318b7d7a 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
+++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
@@ -42,7 +42,7 @@
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/system/simple_watcher.h"
 #include "services/network/public/mojom/websocket.mojom-blink.h"
-#include "third_party/blink/public/mojom/websockets/websocket_connector.mojom-blink.h"
+#include "third_party/blink/public/mojom/websockets/websocket_connector.mojom-blink-forward.h"
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
 #include "third_party/blink/renderer/core/fileapi/blob.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
diff --git a/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc b/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc
index 7a11e5cb..4231f31 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc
+++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl_test.cc
@@ -14,6 +14,7 @@
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/websockets/websocket_connector.mojom-blink.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/platform/websocket_handshake_throttle.h"
 #include "third_party/blink/renderer/core/dom/document.h"
diff --git a/third_party/blink/renderer/modules/webusb/usb.h b/third_party/blink/renderer/modules/webusb/usb.h
index 39dbd6808..5a8d5415 100644
--- a/third_party/blink/renderer/modules/webusb/usb.h
+++ b/third_party/blink/renderer/modules/webusb/usb.h
@@ -7,7 +7,7 @@
 
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "services/device/public/mojom/usb_manager.mojom-blink.h"
+#include "services/device/public/mojom/usb_manager.mojom-blink-forward.h"
 #include "services/device/public/mojom/usb_manager_client.mojom-blink.h"
 #include "third_party/blink/public/mojom/usb/web_usb_service.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
diff --git a/third_party/blink/renderer/modules/xr/xr_anchor.h b/third_party/blink/renderer/modules/xr/xr_anchor.h
index 4848022..2cc7d98 100644
--- a/third_party/blink/renderer/modules/xr/xr_anchor.h
+++ b/third_party/blink/renderer/modules/xr/xr_anchor.h
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "base/optional.h"
-#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
 
diff --git a/third_party/blink/renderer/modules/xr/xr_frame.h b/third_party/blink/renderer/modules/xr/xr_frame.h
index 30186c9..8cbd0fb 100644
--- a/third_party/blink/renderer/modules/xr/xr_frame.h
+++ b/third_party/blink/renderer/modules/xr/xr_frame.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 
-#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
diff --git a/third_party/blink/renderer/modules/xr/xr_hit_test_source.cc b/third_party/blink/renderer/modules/xr/xr_hit_test_source.cc
index b3d8da4..f1435ee 100644
--- a/third_party/blink/renderer/modules/xr/xr_hit_test_source.cc
+++ b/third_party/blink/renderer/modules/xr/xr_hit_test_source.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/modules/xr/xr_hit_test_source.h"
 
+#include "device/vr/public/mojom/vr_service.mojom-blink.h"
 #include "third_party/blink/renderer/modules/xr/xr_hit_test_options.h"
 #include "third_party/blink/renderer/modules/xr/xr_hit_test_result.h"
 
diff --git a/third_party/blink/renderer/modules/xr/xr_hit_test_source.h b/third_party/blink/renderer/modules/xr/xr_hit_test_source.h
index 9dad80a..78c6c0b0 100644
--- a/third_party/blink/renderer/modules/xr/xr_hit_test_source.h
+++ b/third_party/blink/renderer/modules/xr/xr_hit_test_source.h
@@ -9,7 +9,7 @@
 
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 
-#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
 #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/xr/xr_input_source.h b/third_party/blink/renderer/modules/xr/xr_input_source.h
index c05bac0..492043d 100644
--- a/third_party/blink/renderer/modules/xr/xr_input_source.h
+++ b/third_party/blink/renderer/modules/xr/xr_input_source.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_H_
 
-#include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
 #include "third_party/blink/renderer/modules/gamepad/gamepad.h"
 #include "third_party/blink/renderer/modules/xr/xr_native_origin_information.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
diff --git a/third_party/blink/renderer/platform/audio/audio_bus.cc b/third_party/blink/renderer/platform/audio/audio_bus.cc
index 93a9199..e2162d0 100644
--- a/third_party/blink/renderer/platform/audio/audio_bus.cc
+++ b/third_party/blink/renderer/platform/audio/audio_bus.cc
@@ -45,7 +45,8 @@
 
 namespace blink {
 
-using namespace vector_math;
+using vector_math::Vadd;
+using vector_math::Vsma;
 
 const unsigned kMaxBusChannels = 32;
 
@@ -527,8 +528,8 @@
   } else {
     for (unsigned channel_index = 0; channel_index < number_of_channels;
          ++channel_index) {
-      Vsmul(sources[channel_index], 1, &gain, destinations[channel_index], 1,
-            frames_to_process);
+      vector_math::Vsmul(sources[channel_index], 1, &gain,
+                         destinations[channel_index], 1, frames_to_process);
     }
   }
 }
@@ -562,7 +563,8 @@
     if (source_bus.NumberOfChannels() == NumberOfChannels())
       source = source_bus.Channel(channel_index)->Data();
     float* destination = Channel(channel_index)->MutableData();
-    Vmul(source, 1, gain_values, 1, destination, 1, number_of_gain_values);
+    vector_math::Vmul(source, 1, gain_values, 1, destination, 1,
+                      number_of_gain_values);
   }
 }
 
diff --git a/third_party/blink/renderer/platform/audio/audio_channel.cc b/third_party/blink/renderer/platform/audio/audio_channel.cc
index e4b6950..c32867e 100644
--- a/third_party/blink/renderer/platform/audio/audio_channel.cc
+++ b/third_party/blink/renderer/platform/audio/audio_channel.cc
@@ -35,8 +35,6 @@
 
 namespace blink {
 
-using namespace vector_math;
-
 void AudioChannel::ResizeSmaller(size_t new_length) {
   DCHECK_LE(new_length, length_);
   length_ = new_length;
@@ -46,7 +44,7 @@
   if (IsSilent())
     return;
 
-  Vsmul(Data(), 1, &scale, MutableData(), 1, length());
+  vector_math::Vsmul(Data(), 1, &scale, MutableData(), 1, length());
 }
 
 void AudioChannel::CopyFrom(const AudioChannel* source_channel) {
@@ -98,10 +96,12 @@
   if (source_channel->IsSilent())
     return;
 
-  if (IsSilent())
+  if (IsSilent()) {
     CopyFrom(source_channel);
-  else
-    Vadd(Data(), 1, source_channel->Data(), 1, MutableData(), 1, length());
+  } else {
+    vector_math::Vadd(Data(), 1, source_channel->Data(), 1, MutableData(), 1,
+                      length());
+  }
 }
 
 float AudioChannel::MaxAbsValue() const {
@@ -110,7 +110,7 @@
 
   float max = 0;
 
-  Vmaxmgv(Data(), 1, &max, length());
+  vector_math::Vmaxmgv(Data(), 1, &max, length());
 
   return max;
 }
diff --git a/third_party/blink/renderer/platform/audio/dynamics_compressor.cc b/third_party/blink/renderer/platform/audio/dynamics_compressor.cc
index 2768fcb..ac01b96 100644
--- a/third_party/blink/renderer/platform/audio/dynamics_compressor.cc
+++ b/third_party/blink/renderer/platform/audio/dynamics_compressor.cc
@@ -33,8 +33,6 @@
 
 namespace blink {
 
-using namespace audio_utilities;
-
 DynamicsCompressor::DynamicsCompressor(float sample_rate,
                                        unsigned number_of_channels)
     : number_of_channels_(number_of_channels),
diff --git a/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.cc b/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.cc
index b57bf9c..daec0ece 100644
--- a/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.cc
+++ b/third_party/blink/renderer/platform/audio/dynamics_compressor_kernel.cc
@@ -36,8 +36,6 @@
 
 namespace blink {
 
-using namespace audio_utilities;
-
 // Metering hits peaks instantly, but releases this fast (in seconds).
 const float kMeteringReleaseTimeConstant = 0.325f;
 
@@ -63,8 +61,9 @@
   // Initializes most member variables
   Reset();
 
-  metering_release_k_ = static_cast<float>(DiscreteTimeConstantForSampleRate(
-      kMeteringReleaseTimeConstant, sample_rate));
+  metering_release_k_ =
+      float{audio_utilities::DiscreteTimeConstantForSampleRate(
+          kMeteringReleaseTimeConstant, sample_rate)};
 }
 
 void DynamicsCompressorKernel::SetNumberOfChannels(
@@ -114,10 +113,10 @@
     y = KneeCurve(x, k);
   else {
     // Constant ratio after knee.
-    float x_db = LinearToDecibels(x);
+    float x_db = audio_utilities::LinearToDecibels(x);
     float y_db = yknee_threshold_db_ + slope_ * (x_db - knee_threshold_db_);
 
-    y = DecibelsToLinear(y_db);
+    y = audio_utilities::DecibelsToLinear(y_db);
   }
 
   return y;
@@ -132,11 +131,11 @@
 
   float x2 = x * 1.001;
 
-  float x_db = LinearToDecibels(x);
-  float x2_db = LinearToDecibels(x2);
+  float x_db = audio_utilities::LinearToDecibels(x);
+  float x2_db = audio_utilities::LinearToDecibels(x2);
 
-  float y_db = LinearToDecibels(KneeCurve(x, k));
-  float y2_db = LinearToDecibels(KneeCurve(x2, k));
+  float y_db = audio_utilities::LinearToDecibels(KneeCurve(x, k));
+  float y2_db = audio_utilities::LinearToDecibels(KneeCurve(x2, k));
 
   float m = (y2_db - y_db) / (x2_db - x_db);
 
@@ -145,7 +144,7 @@
 
 float DynamicsCompressorKernel::KAtSlope(float desired_slope) {
   float x_db = db_threshold_ + db_knee_;
-  float x = DecibelsToLinear(x_db);
+  float x = audio_utilities::DecibelsToLinear(x_db);
 
   // Approximate k given initial values.
   float min_k = 0.1;
@@ -178,7 +177,7 @@
   if (db_threshold != db_threshold_ || db_knee != db_knee_ || ratio != ratio_) {
     // Threshold and knee.
     db_threshold_ = db_threshold;
-    linear_threshold_ = DecibelsToLinear(db_threshold);
+    linear_threshold_ = audio_utilities::DecibelsToLinear(db_threshold);
     db_knee_ = db_knee;
 
     // Compute knee parameters.
@@ -188,9 +187,10 @@
     float k = KAtSlope(1 / ratio_);
 
     knee_threshold_db_ = db_threshold + db_knee;
-    knee_threshold_ = DecibelsToLinear(knee_threshold_db_);
+    knee_threshold_ = audio_utilities::DecibelsToLinear(knee_threshold_db_);
 
-    yknee_threshold_db_ = LinearToDecibels(KneeCurve(knee_threshold_, k));
+    yknee_threshold_db_ =
+        audio_utilities::LinearToDecibels(KneeCurve(knee_threshold_, k));
 
     knee_ = k;
   }
@@ -233,7 +233,7 @@
   full_range_makeup_gain = powf(full_range_makeup_gain, 0.6f);
 
   float master_linear_gain =
-      DecibelsToLinear(db_post_gain) * full_range_makeup_gain;
+      audio_utilities::DecibelsToLinear(db_post_gain) * full_range_makeup_gain;
 
   // Attack parameters.
   attack_time = std::max(0.001f, attack_time);
@@ -317,8 +317,8 @@
     if (scaled_desired_gain == 0) {
       compression_diff_db = is_releasing ? -1 : 1;
     } else {
-      compression_diff_db =
-          LinearToDecibels(compressor_gain_ / scaled_desired_gain);
+      compression_diff_db = audio_utilities::LinearToDecibels(
+          compressor_gain_ / scaled_desired_gain);
     }
 
     if (is_releasing) {
@@ -352,7 +352,7 @@
 #define kSpacingDb 5
       float db_per_frame = kSpacingDb / calc_release_frames;
 
-      envelope_rate = DecibelsToLinear(db_per_frame);
+      envelope_rate = audio_utilities::DecibelsToLinear(db_per_frame);
     } else {
       // Attack mode - compressionDiffDb should be positive dB
 
@@ -417,12 +417,13 @@
 
         float attenuation = abs_input <= 0.0001f ? 1 : shaped_input / abs_input;
 
-        float attenuation_db = -LinearToDecibels(attenuation);
+        float attenuation_db = -audio_utilities::LinearToDecibels(attenuation);
         attenuation_db = std::max(2.0f, attenuation_db);
 
         float db_per_frame = attenuation_db / sat_release_frames;
 
-        float sat_release_rate = DecibelsToLinear(db_per_frame) - 1;
+        float sat_release_rate =
+            audio_utilities::DecibelsToLinear(db_per_frame) - 1;
 
         bool is_release = (attenuation > detector_average);
         float rate = is_release ? sat_release_rate : 1;
diff --git a/third_party/blink/renderer/platform/audio/fft_convolver.cc b/third_party/blink/renderer/platform/audio/fft_convolver.cc
index 6531386..a01b3fec 100644
--- a/third_party/blink/renderer/platform/audio/fft_convolver.cc
+++ b/third_party/blink/renderer/platform/audio/fft_convolver.cc
@@ -31,8 +31,6 @@
 
 namespace blink {
 
-using namespace vector_math;
-
 FFTConvolver::FFTConvolver(size_t fft_size)
     : frame_(fft_size),
       read_write_index_(0),
@@ -88,8 +86,8 @@
       frame_.DoInverseFFT(output_buffer_.Data());
 
       // Overlap-add 1st half from previous time
-      Vadd(output_buffer_.Data(), 1, last_overlap_buffer_.Data(), 1,
-           output_buffer_.Data(), 1, half_size);
+      vector_math::Vadd(output_buffer_.Data(), 1, last_overlap_buffer_.Data(),
+                        1, output_buffer_.Data(), 1, half_size);
 
       // Finally, save 2nd half of result
       DCHECK_EQ(output_buffer_.size(), 2 * half_size);
diff --git a/third_party/blink/renderer/platform/audio/reverb.cc b/third_party/blink/renderer/platform/audio/reverb.cc
index 392e709..e7eca7d 100644
--- a/third_party/blink/renderer/platform/audio/reverb.cc
+++ b/third_party/blink/renderer/platform/audio/reverb.cc
@@ -41,8 +41,6 @@
 
 namespace blink {
 
-using namespace vector_math;
-
 // Empirical gain calibration tested across many impulse responses to ensure
 // perceived volume is same as dry (unprocessed) signal
 const float kGainCalibration = -58;
@@ -61,7 +59,8 @@
 
   for (size_t i = 0; i < number_of_channels; ++i) {
     float channel_power = 0;
-    Vsvesq(response->Channel(i)->Data(), 1, &channel_power, length);
+    vector_math::Vsvesq(response->Channel(i)->Data(), 1, &channel_power,
+                        length);
     power += channel_power;
   }
 
diff --git a/third_party/blink/renderer/platform/audio/reverb_accumulation_buffer.cc b/third_party/blink/renderer/platform/audio/reverb_accumulation_buffer.cc
index fe801b8..b92806e 100644
--- a/third_party/blink/renderer/platform/audio/reverb_accumulation_buffer.cc
+++ b/third_party/blink/renderer/platform/audio/reverb_accumulation_buffer.cc
@@ -32,8 +32,6 @@
 
 namespace blink {
 
-using namespace vector_math;
-
 ReverbAccumulationBuffer::ReverbAccumulationBuffer(size_t length)
     : buffer_(length), read_index_(0), read_time_frame_(0) {}
 
@@ -90,13 +88,14 @@
   DCHECK_LE(number_of_frames1 + write_index, buffer_length);
   DCHECK_LE(number_of_frames2, buffer_length);
 
-  Vadd(source, 1, destination + write_index, 1, destination + write_index, 1,
-       number_of_frames1);
+  vector_math::Vadd(source, 1, destination + write_index, 1,
+                    destination + write_index, 1, number_of_frames1);
 
   // Handle wrap-around if necessary
-  if (number_of_frames2 > 0)
-    Vadd(source + number_of_frames1, 1, destination, 1, destination, 1,
-         number_of_frames2);
+  if (number_of_frames2 > 0) {
+    vector_math::Vadd(source + number_of_frames1, 1, destination, 1,
+                      destination, 1, number_of_frames2);
+  }
 
   return write_index;
 }
diff --git a/third_party/blink/renderer/platform/audio/reverb_convolver.cc b/third_party/blink/renderer/platform/audio/reverb_convolver.cc
index 5bd54e4c..68b923b 100644
--- a/third_party/blink/renderer/platform/audio/reverb_convolver.cc
+++ b/third_party/blink/renderer/platform/audio/reverb_convolver.cc
@@ -41,8 +41,6 @@
 
 namespace blink {
 
-using namespace vector_math;
-
 const int kInputBufferSize = 8 * 16384;
 
 // We only process the leading portion of the impulse response in the real-time
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index c5dac37..c4fd374 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -501,10 +501,6 @@
   RuntimeEnabledFeatures::SetPresentationEnabled(enable);
 }
 
-void WebRuntimeFeatures::EnableResourceLoadScheduler(bool enable) {
-  RuntimeEnabledFeatures::SetResourceLoadSchedulerEnabled(enable);
-}
-
 void WebRuntimeFeatures::EnableRestrictAutomaticLazyFrameLoadingToDataSaver(
     bool enable) {
   RuntimeEnabledFeatures::
diff --git a/third_party/blink/renderer/platform/exported/web_url_response.cc b/third_party/blink/renderer/platform/exported/web_url_response.cc
index 5d2e4f4..e8eca6af 100644
--- a/third_party/blink/renderer/platform/exported/web_url_response.cc
+++ b/third_party/blink/renderer/platform/exported/web_url_response.cc
@@ -244,7 +244,7 @@
   resource_response_->SetIsLegacyTLSVersion(value);
 }
 
-void WebURLResponse::SetSecurityStyle(WebSecurityStyle security_style) {
+void WebURLResponse::SetSecurityStyle(SecurityStyle security_style) {
   resource_response_->SetSecurityStyle(security_style);
 }
 
diff --git a/third_party/blink/renderer/platform/heap/BUILD.gn b/third_party/blink/renderer/platform/heap/BUILD.gn
index d696d261..43fabbc3 100644
--- a/third_party/blink/renderer/platform/heap/BUILD.gn
+++ b/third_party/blink/renderer/platform/heap/BUILD.gn
@@ -139,6 +139,7 @@
     "persistent_test.cc",
     "thread_state_scheduling_test.cc",
     "worklist_test.cc",
+    "write_barrier_perftest.cc",
   ]
 
   configs += [
diff --git a/third_party/blink/renderer/platform/heap/DEPS b/third_party/blink/renderer/platform/heap/DEPS
index 86e14cda8..eda4c2e 100644
--- a/third_party/blink/renderer/platform/heap/DEPS
+++ b/third_party/blink/renderer/platform/heap/DEPS
@@ -13,6 +13,7 @@
     "+base/synchronization/lock.h",
     "+base/task_runner.h",
     "+base/template_util.h",
+    "+testing/perf/perf_test.h",
 
     "+third_party/blink/renderer/platform/bindings",
     "+third_party/blink/renderer/platform/instrumentation/histogram.h",
diff --git a/third_party/blink/renderer/platform/heap/OWNERS b/third_party/blink/renderer/platform/heap/OWNERS
index cf641ac..3e3e9ca5 100644
--- a/third_party/blink/renderer/platform/heap/OWNERS
+++ b/third_party/blink/renderer/platform/heap/OWNERS
@@ -1,3 +1,4 @@
+bikineev@chromium.org
 erik.corry@gmail.com
 haraken@chromium.org
 kouhei@chromium.org
diff --git a/third_party/blink/renderer/platform/heap/heap_page.h b/third_party/blink/renderer/platform/heap/heap_page.h
index 58826db..51ae8806 100644
--- a/third_party/blink/renderer/platform/heap/heap_page.h
+++ b/third_party/blink/renderer/platform/heap/heap_page.h
@@ -507,14 +507,6 @@
   virtual void PoisonUnmarkedObjects() = 0;
 #endif
 
-  class HeapSnapshotInfo {
-    STACK_ALLOCATED();
-
-   public:
-    size_t free_count = 0;
-    size_t free_size = 0;
-  };
-
   virtual void CollectStatistics(
       ThreadState::Statistics::ArenaStatistics* arena_stats) = 0;
 
diff --git a/third_party/blink/renderer/platform/heap/trace_traits.h b/third_party/blink/renderer/platform/heap/trace_traits.h
index ac051c1..cfbd628 100644
--- a/third_party/blink/renderer/platform/heap/trace_traits.h
+++ b/third_party/blink/renderer/platform/heap/trace_traits.h
@@ -580,19 +580,18 @@
 
 // Nodes used by LinkedHashSet.  Again we need two versions to disambiguate the
 // template.
-template <typename Value, typename Allocator, typename Traits>
+template <typename Value, typename Traits>
 struct TraceInCollectionTrait<kNoWeakHandling,
-                              LinkedHashSetNode<Value, Allocator>,
+                              LinkedHashSetNode<Value>,
                               Traits> {
-  static bool IsAlive(LinkedHashSetNode<Value, Allocator>& self) {
+  static bool IsAlive(LinkedHashSetNode<Value>& self) {
     return TraceInCollectionTrait<
         kNoWeakHandling, Value,
         typename Traits::ValueTraits>::IsAlive(self.value_);
   }
 
   template <typename VisitorDispatcher>
-  static bool Trace(VisitorDispatcher visitor,
-                    LinkedHashSetNode<Value, Allocator>& self) {
+  static bool Trace(VisitorDispatcher visitor, LinkedHashSetNode<Value>& self) {
     static_assert(IsTraceableInCollectionTrait<Traits>::value ||
                       Traits::kWeakHandlingFlag == WTF::kWeakHandling,
                   "T should not be traced");
@@ -602,19 +601,16 @@
   }
 };
 
-template <typename Value, typename Allocator, typename Traits>
-struct TraceInCollectionTrait<kWeakHandling,
-                              LinkedHashSetNode<Value, Allocator>,
-                              Traits> {
-  static bool IsAlive(LinkedHashSetNode<Value, Allocator>& self) {
+template <typename Value, typename Traits>
+struct TraceInCollectionTrait<kWeakHandling, LinkedHashSetNode<Value>, Traits> {
+  static bool IsAlive(LinkedHashSetNode<Value>& self) {
     return TraceInCollectionTrait<
         kWeakHandling, Value,
         typename Traits::ValueTraits>::IsAlive(self.value_);
   }
 
   template <typename VisitorDispatcher>
-  static bool Trace(VisitorDispatcher visitor,
-                    LinkedHashSetNode<Value, Allocator>& self) {
+  static bool Trace(VisitorDispatcher visitor, LinkedHashSetNode<Value>& self) {
     return TraceInCollectionTrait<
         kWeakHandling, Value, typename Traits::ValueTraits>::Trace(visitor,
                                                                    self.value_);
diff --git a/third_party/blink/renderer/platform/heap/write_barrier_perftest.cc b/third_party/blink/renderer/platform/heap/write_barrier_perftest.cc
new file mode 100644
index 0000000..b473c53
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/write_barrier_perftest.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+#include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+
+namespace blink {
+
+class WriteBarrierPerfTest : public TestSupportingGC {};
+
+namespace {
+
+class SimpleObject : public GarbageCollected<SimpleObject> {
+ public:
+  SimpleObject() = default;
+  virtual void Trace(Visitor*) {}
+};
+
+base::TimeDelta TimedRun(base::RepeatingCallback<void()> callback) {
+  const base::TimeTicks start = base::TimeTicks::Now();
+  callback.Run();
+  return base::TimeTicks::Now() - start;
+}
+
+}  // namespace
+
+TEST_F(WriteBarrierPerfTest, MemberWritePerformance) {
+  // Setup.
+  constexpr wtf_size_t kNumElements = 100000;
+  Persistent<HeapVector<Member<SimpleObject>>> holder(
+      MakeGarbageCollected<HeapVector<Member<SimpleObject>>>());
+  for (wtf_size_t i = 0; i < kNumElements; ++i) {
+    holder->push_back(MakeGarbageCollected<SimpleObject>());
+  }
+  PreciselyCollectGarbage();
+  // Benchmark.
+  base::RepeatingCallback<void()> benchmark = base::BindRepeating(
+      [](const Persistent<HeapVector<Member<SimpleObject>>>& holder) {
+        for (wtf_size_t i = 0; i < kNumElements / 2; ++i) {
+          (*holder)[i].Swap((*holder)[kNumElements / 2 + i]);
+        }
+      },
+      holder);
+
+  // During GC.
+  IncrementalMarkingTestDriver driver(ThreadState::Current());
+  driver.Start();
+  base::TimeDelta during_gc_duration = TimedRun(benchmark);
+  driver.FinishSteps();
+  PreciselyCollectGarbage();
+
+  // Outside GC.
+  base::TimeDelta outside_gc_duration = TimedRun(benchmark);
+
+  // Cleanup.
+  holder.Clear();
+  PreciselyCollectGarbage();
+
+  // Reporting.
+  perf_test::PrintResult(
+      "WriteBarrierPerfTest", " writes during GC", "",
+      static_cast<double>(kNumElements) / during_gc_duration.InMillisecondsF(),
+      "writes/ms", true);
+  perf_test::PrintResult(
+      "WriteBarrierPerfTest", " writes outside GC", "",
+      static_cast<double>(kNumElements) / outside_gc_duration.InMillisecondsF(),
+      "writes/ms", true);
+  perf_test::PrintResult("WriteBarrierPerfTest", " relative speed difference",
+                         "",
+                         during_gc_duration.InMillisecondsF() /
+                             outside_gc_duration.InMillisecondsF(),
+                         "times", true);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
index c981ff8..6496f9f 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
@@ -89,9 +89,6 @@
 
 size_t GetOutstandingThrottledLimit(
     const DetachableResourceFetcherProperties& properties) {
-  if (!RuntimeEnabledFeatures::ResourceLoadSchedulerEnabled())
-    return ResourceLoadScheduler::kOutstandingUnlimited;
-
   static const size_t main_frame_limit = GetFieldTrialUint32Param(
       kResourceLoadThrottlingTrial, kOutstandingLimitForBackgroundMainFrameName,
       kOutstandingLimitForBackgroundMainFrameDefault);
@@ -108,10 +105,6 @@
   return kilobytes;
 }
 
-bool IsResourceLoadThrottlingEnabled() {
-  return RuntimeEnabledFeatures::ResourceLoadSchedulerEnabled();
-}
-
 }  // namespace
 
 // A class to gather throttling and traffic information to report histograms.
@@ -377,9 +370,7 @@
       return throttleable;
     case scheduler::SchedulingLifecycleState::kHidden:
     case scheduler::SchedulingLifecycleState::kThrottled:
-      if (IsResourceLoadThrottlingEnabled())
-        return option == ThrottleOption::kThrottleable;
-      return throttleable;
+      return option == ThrottleOption::kThrottleable;
     case scheduler::SchedulingLifecycleState::kStopped:
       return stoppable;
   }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler_test.cc
index baf1d5c..a5056c1 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler_test.cc
@@ -89,7 +89,6 @@
 
   using ThrottleOption = ResourceLoadScheduler::ThrottleOption;
   void SetUp() override {
-    DCHECK(RuntimeEnabledFeatures::ResourceLoadSchedulerEnabled());
     auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
     properties->SetShouldBlockLoadingSubResource(true);
     auto frame_scheduler = std::make_unique<scheduler::FakeFrameScheduler>();
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_response.cc b/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
index d258b67..9db2d03 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
@@ -232,8 +232,8 @@
     time_t valid_to,
     const Vector<AtomicString>& certificate,
     const SignedCertificateTimestampList& sct_list) {
-  DCHECK_NE(security_style_, kWebSecurityStyleUnknown);
-  DCHECK_NE(security_style_, kWebSecurityStyleNeutral);
+  DCHECK_NE(security_style_, SecurityStyle::kUnknown);
+  DCHECK_NE(security_style_, SecurityStyle::kNeutral);
   security_details_ = SecurityDetails(
       protocol, key_exchange, key_exchange_group, cipher, mac, subject_name,
       san_list, issuer, valid_from, valid_to, certificate, sct_list);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_response.h b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
index 3c200c17..6f24450 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_response.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
@@ -280,8 +280,8 @@
   bool IsLegacyTLSVersion() const { return is_legacy_tls_version_; }
   void SetIsLegacyTLSVersion(bool value) { is_legacy_tls_version_ = value; }
 
-  WebSecurityStyle GetSecurityStyle() const { return security_style_; }
-  void SetSecurityStyle(WebSecurityStyle security_style) {
+  SecurityStyle GetSecurityStyle() const { return security_style_; }
+  void SetSecurityStyle(SecurityStyle security_style) {
     security_style_ = security_style;
   }
 
@@ -554,7 +554,7 @@
   // The security style of the resource.
   // This only contains a valid value when the DevTools Network domain is
   // enabled. (Otherwise, it contains a default value of Unknown.)
-  WebSecurityStyle security_style_ = kWebSecurityStyleUnknown;
+  SecurityStyle security_style_ = SecurityStyle::kUnknown;
 
   // Security details of this request's connection.
   base::Optional<SecurityDetails> security_details_;
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
index cd34c21..e495bf0 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
@@ -372,15 +372,8 @@
   media::VideoPixelFormat pixel_format = media::PIXEL_FORMAT_I420;
   auto storage_type =
       media::VideoEncodeAccelerator::Config::StorageType::kShmem;
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kVideoCaptureUseGpuMemoryBuffer) &&
-      video_content_type_ != webrtc::VideoContentType::SCREENSHARE) {
-    // Use import mode for camera when GpuMemoryBuffer-based video capture is
-    // enabled.
-    pixel_format = media::PIXEL_FORMAT_NV12;
-    storage_type = media::VideoEncodeAccelerator::Config::StorageType::kDmabuf;
-    use_native_input_ = true;
-  }
+  // TODO(crbug.com/1014209): Enable native input mode after fake video capture
+  // device supports delivering GpuMemoryBuffer frames.
   const media::VideoEncodeAccelerator::Config config(
       pixel_format, input_visible_size_, profile, bitrate * 1000, base::nullopt,
       base::nullopt, base::nullopt, storage_type,
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 464177a..5a0af5e 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1349,10 +1349,6 @@
       status: {"Android": "stable", "default": ""},
     },
     {
-      name: "ResourceLoadScheduler",
-      status: "experimental",
-    },
-    {
       name: "RestrictAppCacheToSecureContexts",
       status: "stable",
     },
diff --git a/third_party/blink/renderer/platform/text_codec_fuzzer.cc b/third_party/blink/renderer/platform/text_codec_fuzzer.cc
index 41d9798..28a477f5 100644
--- a/third_party/blink/renderer/platform/text_codec_fuzzer.cc
+++ b/third_party/blink/renderer/platform/text_codec_fuzzer.cc
@@ -9,8 +9,6 @@
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding_registry.h"
 
-using namespace blink;
-
 // TODO(jsbell): This fuzzes code in wtf/ but has dependencies on platform/,
 // so it must live in the latter directory. Once wtf/ moves into platform/wtf
 // this should move there as well.
@@ -27,7 +25,7 @@
 
 // Fuzzer for WTF::TextCodec.
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  static BlinkFuzzerTestSupport test_support = BlinkFuzzerTestSupport();
+  static blink::BlinkFuzzerTestSupport test_support;
   // The fuzzer picks 3 bytes off the end of the data to initialize metadata, so
   // abort if the input is smaller than that.
   if (size < 3)
diff --git a/third_party/blink/renderer/platform/wtf/decimal.cc b/third_party/blink/renderer/platform/wtf/decimal.cc
index c6d881d..58720c9 100644
--- a/third_party/blink/renderer/platform/wtf/decimal.cc
+++ b/third_party/blink/renderer/platform/wtf/decimal.cc
@@ -40,13 +40,13 @@
 
 namespace blink {
 
-namespace decimal_private {
+namespace {
 
-static int const kExponentMax = 1023;
-static int const kExponentMin = -1023;
-static int const kPrecision = 18;
+constexpr int kExponentMax = 1023;
+constexpr int kExponentMin = -1023;
+constexpr int kPrecision = 18;
 
-static const uint64_t kMaxCoefficient =
+constexpr uint64_t kMaxCoefficient =
     UINT64_C(0xDE0B6B3A763FFFF);  // 999999999999999999 == 18 9's
 
 // This class handles Decimal special values.
@@ -75,54 +75,38 @@
 
   const Decimal& lhs_;
   const Decimal& rhs_;
-  Result result_;
+  Result result_ = kResultIsUnknown;
 
   DISALLOW_COPY_AND_ASSIGN(SpecialValueHandler);
 };
 
 SpecialValueHandler::SpecialValueHandler(const Decimal& lhs, const Decimal& rhs)
-    : lhs_(lhs), rhs_(rhs), result_(kResultIsUnknown) {}
+    : lhs_(lhs), rhs_(rhs) {}
 
 SpecialValueHandler::HandleResult SpecialValueHandler::Handle() {
   if (lhs_.IsFinite() && rhs_.IsFinite())
     return kBothFinite;
 
-  const Decimal::EncodedData::FormatClass lhs_class =
-      lhs_.Value().GetFormatClass();
-  const Decimal::EncodedData::FormatClass rhs_class =
-      rhs_.Value().GetFormatClass();
-  if (lhs_class == Decimal::EncodedData::kClassNaN) {
+  if (lhs_.IsNaN()) {
     result_ = kResultIsLHS;
     return kEitherNaN;
   }
 
-  if (rhs_class == Decimal::EncodedData::kClassNaN) {
+  if (rhs_.IsNaN()) {
     result_ = kResultIsRHS;
     return kEitherNaN;
   }
 
-  if (lhs_class == Decimal::EncodedData::kClassInfinity)
-    return rhs_class == Decimal::EncodedData::kClassInfinity ? kBothInfinity
-                                                             : kLHSIsInfinity;
+  if (lhs_.IsInfinity())
+    return rhs_.IsInfinity() ? kBothInfinity : kLHSIsInfinity;
 
-  if (rhs_class == Decimal::EncodedData::kClassInfinity)
-    return kRHSIsInfinity;
-
-  NOTREACHED();
-  return kBothFinite;
+  DCHECK(rhs_.IsInfinity());
+  return kRHSIsInfinity;
 }
 
 Decimal SpecialValueHandler::Value() const {
-  switch (result_) {
-    case kResultIsLHS:
-      return lhs_;
-    case kResultIsRHS:
-      return rhs_;
-    case kResultIsUnknown:
-    default:
-      NOTREACHED();
-      return lhs_;
-  }
+  DCHECK(result_ == kResultIsLHS || result_ == kResultIsRHS);
+  return (result_ == kResultIsLHS) ? lhs_ : rhs_;
 }
 
 // This class is used for 128 bit unsigned integer arithmetic.
@@ -232,9 +216,7 @@
   }
 }
 
-}  // namespace decimal_private
-
-using namespace decimal_private;
+}  // namespace
 
 Decimal::EncodedData::EncodedData(Sign sign, FormatClass format_class)
     : coefficient_(0), exponent_(0), format_class_(format_class), sign_(sign) {}
diff --git a/third_party/blink/renderer/platform/wtf/decimal.h b/third_party/blink/renderer/platform/wtf/decimal.h
index 1ba7091a..98e5a4a 100644
--- a/third_party/blink/renderer/platform/wtf/decimal.h
+++ b/third_party/blink/renderer/platform/wtf/decimal.h
@@ -39,10 +39,6 @@
 
 namespace blink {
 
-namespace decimal_private {
-class SpecialValueHandler;
-}
-
 // This class represents decimal base floating point number.
 //
 // FIXME: Once all C++ compiler support decimal type, we should replace this
@@ -63,7 +59,6 @@
     DISALLOW_NEW();
     // For accessing FormatClass.
     friend class Decimal;
-    friend class decimal_private::SpecialValueHandler;
 
    public:
     EncodedData(Sign, int exponent, uint64_t coefficient);
diff --git a/third_party/blink/renderer/platform/wtf/linked_hash_set.h b/third_party/blink/renderer/platform/wtf/linked_hash_set.h
index 71ef37a..1f0e0105 100644
--- a/third_party/blink/renderer/platform/wtf/linked_hash_set.h
+++ b/third_party/blink/renderer/platform/wtf/linked_hash_set.h
@@ -136,7 +136,7 @@
   LinkedHashSetNodeBase& operator=(const LinkedHashSetNodeBase& other) = delete;
 };
 
-template <typename ValueArg, typename Allocator>
+template <typename ValueArg>
 class LinkedHashSetNode : public LinkedHashSetNodeBase {
   DISALLOW_NEW();
 
@@ -171,7 +171,7 @@
  private:
   typedef ValueArg Value;
   typedef TraitsArg Traits;
-  typedef LinkedHashSetNode<Value, Allocator> Node;
+  typedef LinkedHashSetNode<Value> Node;
   typedef LinkedHashSetNodeBase NodeBase;
   typedef LinkedHashSetTranslator<Value, HashFunctions, Allocator>
       NodeHashFunctions;
@@ -361,7 +361,7 @@
 template <typename Value, typename HashFunctions, typename Allocator>
 struct LinkedHashSetTranslator {
   STATIC_ONLY(LinkedHashSetTranslator);
-  typedef LinkedHashSetNode<Value, Allocator> Node;
+  typedef LinkedHashSetNode<Value> Node;
   typedef LinkedHashSetNodeBase NodeBase;
   typedef typename HashTraits<Value>::PeekInType ValuePeekInType;
   static unsigned GetHash(const Node& node) {
@@ -394,16 +394,16 @@
 template <typename Value, typename Allocator>
 struct LinkedHashSetExtractor {
   STATIC_ONLY(LinkedHashSetExtractor);
-  static const Value& Extract(const LinkedHashSetNode<Value, Allocator>& node) {
+  static const Value& Extract(const LinkedHashSetNode<Value>& node) {
     return node.value_;
   }
 };
 
 template <typename Value, typename ValueTraitsArg, typename Allocator>
 struct LinkedHashSetTraits
-    : public SimpleClassHashTraits<LinkedHashSetNode<Value, Allocator>> {
+    : public SimpleClassHashTraits<LinkedHashSetNode<Value>> {
   STATIC_ONLY(LinkedHashSetTraits);
-  using Node = LinkedHashSetNode<Value, Allocator>;
+  using Node = LinkedHashSetNode<Value>;
   using NodeBase = LinkedHashSetNodeBase;
   typedef ValueTraitsArg ValueTraits;
 
@@ -961,8 +961,7 @@
 }
 
 template <typename T, typename Allocator>
-inline void swap(LinkedHashSetNode<T, Allocator>& a,
-                 LinkedHashSetNode<T, Allocator>& b) {
+inline void swap(LinkedHashSetNode<T>& a, LinkedHashSetNode<T>& b) {
   typedef LinkedHashSetNodeBase Base;
   // The key and value cannot be swapped atomically, and it would be
   // wrong to have a GC when only one was swapped and the other still
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-features=OutOfBlinkCors b/third_party/blink/web_tests/FlagExpectations/enable-features=OutOfBlinkCors
index 4c1966a..5241929 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-features=OutOfBlinkCors
+++ b/third_party/blink/web_tests/FlagExpectations/enable-features=OutOfBlinkCors
@@ -28,6 +28,7 @@
 # file to ignore text diffs. It also fails on the same checks even with
 # OOR-CORS, but with different texts. Just mark them as Failure.
 crbug.com/870173 external/wpt/service-workers/service-worker/fetch-request-xhr.https.html [ Failure ]
+crbug.com/870173 virtual/cache-storage-eager-reading/external/wpt/service-workers/service-worker/fetch-request-xhr.https.html [ Failure ]
 crbug.com/870173 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/fetch-request-xhr.https.html [ Failure ]
 crbug.com/870173 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-request-xhr.https.html [ Failure ]
 crbug.com/870173 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/fetch-request-xhr.https.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 48a2c3a..d880db6 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -215,8 +215,6 @@
 crbug.com/730267 virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-layer.html [ Pass Timeout Failure ]
 crbug.com/730267 virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-layer-filter.html [ Pass Timeout Failure ]
 
-crbug.com/1013736 external/wpt/svg/animations/slider-switch.html [ Pass Failure ]
-
 # Flaky virtual/threaded/fast/scrolling tests
 crbug.com/841567 virtual/threaded/fast/scrolling/absolute-position-behind-scrollbar.html [ Failure Pass ]
 crbug.com/841567 virtual/threaded/fast/scrolling/fixed-position-behind-scrollbar.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/animations/web-animations/animation-state-changes-negative-playback-rate.html b/third_party/blink/web_tests/animations/web-animations/animation-state-changes-negative-playback-rate.html
index c3774c6..f9c40f70 100644
--- a/third_party/blink/web_tests/animations/web-animations/animation-state-changes-negative-playback-rate.html
+++ b/third_party/blink/web_tests/animations/web-animations/animation-state-changes-negative-playback-rate.html
@@ -82,7 +82,7 @@
 
 test(function() {
   var animation = finishedAnimation();
-  assert_equals(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime));
+  assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime));
   assert_equals(animation.currentTime, 0);
   assert_false(animation.pending);
   assert_equals(animation.playState, 'finished');
@@ -118,7 +118,7 @@
 test(function() {
   var animation = idleAnimation();
   animation.finish();
-  assert_equals(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime));
+  assert_times_equal(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime));
   assert_equals(animation.currentTime, 0);
   assert_false(animation.pending);
   assert_equals(animation.playState, 'finished');
@@ -221,7 +221,7 @@
   animation.play();
   assert_equals(animation.startTime, startTime);
   assert_equals(animation.currentTime, currentTime);
-  assert_true(animation.pending);
+  assert_false(animation.pending);
   assert_equals(animation.playState, 'running');
 }, "Calling play() on a running animation");
 
diff --git a/third_party/blink/web_tests/animations/web-animations/animation-state-changes-positive-playback-rate.html b/third_party/blink/web_tests/animations/web-animations/animation-state-changes-positive-playback-rate.html
index 0592cbc3..1c3e5930 100644
--- a/third_party/blink/web_tests/animations/web-animations/animation-state-changes-positive-playback-rate.html
+++ b/third_party/blink/web_tests/animations/web-animations/animation-state-changes-positive-playback-rate.html
@@ -212,7 +212,7 @@
   animation.play();
   assert_equals(animation.startTime, startTime);
   assert_equals(animation.currentTime, currentTime);
-  assert_true(animation.pending);
+  assert_false(animation.pending);
   assert_equals(animation.playState, 'running');
 }, "Setting play() on a running animation");
 
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index 9a331dd..9f62231 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -6913,6 +6913,18 @@
      {}
     ]
    ],
+   "web-nfc/NFCReader-document-hidden-manual.https.html": [
+    [
+     "web-nfc/NFCReader-document-hidden-manual.https.html",
+     {}
+    ]
+   ],
+   "web-nfc/NFCWriter-document-hidden-manual.https.html": [
+    [
+     "web-nfc/NFCWriter-document-hidden-manual.https.html",
+     {}
+    ]
+   ],
    "web-share/share-cancel-manual.https.html": [
     [
      "web-share/share-cancel-manual.https.html",
@@ -148135,6 +148147,9 @@
    "css/cssom-view/long_scroll_composited-ref.html": [
     []
    ],
+   "css/cssom-view/matchMediaAddListener-handleEvent-expected.txt": [
+    []
+   ],
    "css/cssom-view/resources/elementsFromPoint.js": [
     []
    ],
@@ -148144,6 +148159,9 @@
    "css/cssom-view/resources/iframe2.html": [
     []
    ],
+   "css/cssom-view/resources/matchMedia.js": [
+    []
+   ],
    "css/cssom-view/scrollIntoView-sideways-lr-writing-mode-expected.txt": [
     []
    ],
@@ -160057,9 +160075,6 @@
    "html/semantics/embedded-content/the-iframe-element/cross_origin_grandchild.html": [
     []
    ],
-   "html/semantics/embedded-content/the-iframe-element/iframe-load-event-expected.txt": [
-    []
-   ],
    "html/semantics/embedded-content/the-iframe-element/iframe-modify-scrolling-attr-to-yes-ref.html": [
     []
    ],
@@ -176173,6 +176188,12 @@
    "web-nfc/META.yml": [
     []
    ],
+   "web-nfc/NFCReader-document-hidden-manual.https-expected.txt": [
+    []
+   ],
+   "web-nfc/NFCWriter-document-hidden-manual.https-expected.txt": [
+    []
+   ],
    "web-nfc/OWNERS": [
     []
    ],
@@ -219897,6 +219918,12 @@
      }
     ]
    ],
+   "css/cssom-view/matchMediaAddListener-handleEvent.html": [
+    [
+     "css/cssom-view/matchMediaAddListener-handleEvent.html",
+     {}
+    ]
+   ],
    "css/cssom-view/matchMediaAddListener.html": [
     [
      "css/cssom-view/matchMediaAddListener.html",
@@ -348491,7 +348518,7 @@
    "reftest"
   ],
   "css/CSS2/linebox/inline-negative-margin-001.html": [
-   "6ebabd15dee475c33a5f003287d9de1973209300",
+   "226a3a19ad17b8fb773e00174b1dcd1593e6be61",
    "testharness"
   ],
   "css/CSS2/linebox/leading-001-ref.xht": [
@@ -420062,6 +420089,14 @@
    "202a3b738dd0d7c83ed9b4cdff8c7212ae09f61e",
    "testharness"
   ],
+  "css/cssom-view/matchMediaAddListener-handleEvent-expected.txt": [
+   "7ee5f624fb9c7e8671695050da2473634084ddbe",
+   "support"
+  ],
+  "css/cssom-view/matchMediaAddListener-handleEvent.html": [
+   "8bc665693d8f722fcd8a1f6fde9d6c36e4ecfd23",
+   "testharness"
+  ],
   "css/cssom-view/matchMediaAddListener.html": [
    "7236be7febc985a9432e3127b78acf352bb91fa1",
    "testharness"
@@ -420142,6 +420177,10 @@
    "7bb944c9d59349b3a25ab14981ae34f5ef991bec",
    "support"
   ],
+  "css/cssom-view/resources/matchMedia.js": [
+   "93f4a31505098033dfe55d8075d7315c590703bb",
+   "support"
+  ],
   "css/cssom-view/screenLeftTop.html": [
    "58d868866eb275724c996bdc1a636ff6173d75a9",
    "testharness"
@@ -453582,12 +453621,8 @@
    "ac8bd5e053b910cfdd8e181709c1f2f039d476b3",
    "testharness"
   ],
-  "html/semantics/embedded-content/the-iframe-element/iframe-load-event-expected.txt": [
-   "b8ee3076b169157e87e662e4f85a929ed9b54674",
-   "support"
-  ],
   "html/semantics/embedded-content/the-iframe-element/iframe-load-event.html": [
-   "d245bf0b96451b3419e0e69bda86fe4859c9cbfe",
+   "5ffe53c308ebed4784543984075deb0e5901be01",
    "testharness"
   ],
   "html/semantics/embedded-content/the-iframe-element/iframe-modify-scrolling-attr-to-yes-ref.html": [
@@ -505319,7 +505354,7 @@
    "support"
   ],
   "tools/wptrunner/wptrunner/browsers/firefox.py": [
-   "781d7e31c43c01c0a33328e1dc921f4f536d5296",
+   "6cf784fd01049a24ad6c8253179ad61d62073774",
    "support"
   ],
   "tools/wptrunner/wptrunner/browsers/firefox_android.py": [
@@ -511298,6 +511333,14 @@
    "1cc9ce160be46955a9b15485ee4c040605722961",
    "testharness"
   ],
+  "web-nfc/NFCReader-document-hidden-manual.https-expected.txt": [
+   "9fba7c80883b5144c3a444df0b6bfb6fef0ebb64",
+   "support"
+  ],
+  "web-nfc/NFCReader-document-hidden-manual.https.html": [
+   "6d9a52c1ecf5bfb2f9ac9876b0ff5988bcc285e0",
+   "manual"
+  ],
   "web-nfc/NFCReader_options.https.html": [
    "5761747f907fad40873023f8ba746bef19fb08e7",
    "testharness"
@@ -511310,6 +511353,14 @@
    "20585176b7f89a129fad99f17d068b2deb828f68",
    "testharness"
   ],
+  "web-nfc/NFCWriter-document-hidden-manual.https-expected.txt": [
+   "777243f850377f2f6a0ef99e452fed18cb9fc2d9",
+   "support"
+  ],
+  "web-nfc/NFCWriter-document-hidden-manual.https.html": [
+   "72d8c8143cd934ad3ff0f8e32968851a1769b0c3",
+   "manual"
+  ],
   "web-nfc/NFCWriter_push.https.html": [
    "dda160f159a23223c0910d2393ecbc8c8e38aed1",
    "testharness"
@@ -512675,7 +512726,7 @@
    "support"
   ],
   "webdriver/tests/element_click/bubbling.py": [
-   "2b08be1f983787f69507176b650e64902577b72d",
+   "a069a5a5df3d7f2bd2851eb4f1a2f9aecdeed86c",
    "wdspec"
   ],
   "webdriver/tests/element_click/center_point.py": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/outline-with-opacity-crash.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/outline-with-opacity-crash.html
new file mode 100644
index 0000000..556e3cf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/outline-with-opacity-crash.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<link rel="author" title="Philip Rogers" href="mailto:pdr@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1011699">
+<span id="target" style="outline: 1px solid black; will-change: opacity; opacity: 0.7;">test</span>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+  test(()=> {
+      target.style.background = "lightblue";
+  }, "no crash");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/matchMediaAddListener-handleEvent-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom-view/matchMediaAddListener-handleEvent-expected.txt
new file mode 100644
index 0000000..7ee5f62
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom-view/matchMediaAddListener-handleEvent-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS calls handleEvent method of event listener
+PASS rethrows errors when getting handleEvent
+PASS looks up handleEvent method on every event dispatch
+PASS doesn't look up handleEvent method on callable event listeners
+FAIL throws if handleEvent is falsy and not callable promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'name' of undefined"
+FAIL throws if handleEvent is thruthy and not callable promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'name' of undefined"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/matchMediaAddListener-handleEvent.html b/third_party/blink/web_tests/external/wpt/css/cssom-view/matchMediaAddListener-handleEvent.html
new file mode 100644
index 0000000..8bc66569
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom-view/matchMediaAddListener-handleEvent.html
@@ -0,0 +1,136 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Test: CSSOM View matchMedia handleEvent via addListener</title>
+<link rel="help" href="https://dom.spec.whatwg.org/#callbackdef-eventlistener">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/matchMedia.js"></script>
+<div id="log"></div>
+<script>
+setup({ allow_uncaught_exception: true });
+
+promise_test(async t => {
+    const iframe = await createIframe(t);
+    const mql = iframe.contentWindow.matchMedia(MEDIA_QUERY);
+
+    let _this;
+    let _event;
+    const eventListener = {
+        handleEvent(event) {
+            _this = this;
+            _event = event;
+        },
+    };
+
+    mql.addListener(eventListener);
+    triggerMQLEvent(iframe);
+    await waitForChangesReported();
+
+    assert_equals(_this, eventListener);
+    assert_equals(_event.matches, mql.matches);
+    assert_equals(_event.media, MEDIA_QUERY);
+}, "calls handleEvent method of event listener");
+
+promise_test(async t => {
+    const iframe = await createIframe(t);
+    const mql = iframe.contentWindow.matchMedia(MEDIA_QUERY);
+
+    let uncaughtError;
+    const errorHandler = event => {
+        uncaughtError = event.error;
+    };
+    window.addEventListener("error", errorHandler);
+    t.add_cleanup(() => {
+        window.removeEventListener("error", errorHandler);
+    });
+
+    const thrownError = { name: "test" };
+    mql.addListener({
+        get handleEvent() {
+            throw thrownError;
+        },
+    });
+
+    triggerMQLEvent(iframe);
+    await waitForChangesReported();
+    assert_equals(uncaughtError, thrownError);
+}, "rethrows errors when getting handleEvent");
+
+promise_test(async t => {
+    const iframe = await createIframe(t);
+    const mql = iframe.contentWindow.matchMedia(MEDIA_QUERY);
+
+    let calls = 0;
+    mql.addListener({
+        get handleEvent() {
+            calls++;
+            return function() {};
+        },
+    });
+    assert_equals(calls, 0);
+
+    triggerMQLEvent(iframe);
+    await waitForChangesReported();
+    assert_equals(calls, 1);
+
+    triggerMQLEvent(iframe);
+    await waitForChangesReported();
+    assert_equals(calls, 2);
+}, "looks up handleEvent method on every event dispatch");
+
+promise_test(async t => {
+    const iframe = await createIframe(t);
+    const mql = iframe.contentWindow.matchMedia(MEDIA_QUERY);
+
+    let calls = 0;
+    const eventListener = function() { calls++; };
+    Object.defineProperty(eventListener, "handleEvent", {
+        get: t.unreached_func("handleEvent method should not be looked up on functions"),
+    });
+    mql.addListener(eventListener);
+
+    triggerMQLEvent(iframe);
+    await waitForChangesReported();
+    assert_equals(calls, 1);
+}, "doesn't look up handleEvent method on callable event listeners");
+
+promise_test(async t => {
+    const iframe = await createIframe(t);
+    const mql = iframe.contentWindow.matchMedia(MEDIA_QUERY);
+
+    let uncaughtError;
+    const errorHandler = event => {
+        uncaughtError = event.error;
+    };
+    window.addEventListener("error", errorHandler);
+    t.add_cleanup(() => {
+        window.removeEventListener("error", errorHandler);
+    });
+
+    mql.addListener({ handleEvent: null });
+    triggerMQLEvent(iframe);
+    await waitForChangesReported();
+
+    assert_equals(uncaughtError.name, "TypeError");
+}, "throws if handleEvent is falsy and not callable");
+
+promise_test(async t => {
+    const iframe = await createIframe(t);
+    const mql = iframe.contentWindow.matchMedia(MEDIA_QUERY);
+
+    let uncaughtError;
+    const errorHandler = event => {
+        uncaughtError = event.error;
+    };
+    window.addEventListener("error", errorHandler);
+    t.add_cleanup(() => {
+        window.removeEventListener("error", errorHandler);
+    });
+
+    mql.addListener({ handleEvent: "str" });
+    triggerMQLEvent(iframe);
+    await waitForChangesReported();
+
+    assert_equals(uncaughtError.name, "TypeError");
+}, "throws if handleEvent is thruthy and not callable");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/resources/matchMedia.js b/third_party/blink/web_tests/external/wpt/css/cssom-view/resources/matchMedia.js
new file mode 100644
index 0000000..93f4a31
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom-view/resources/matchMedia.js
@@ -0,0 +1,32 @@
+const IFRAME_BASE_WIDTH = "200";
+const MEDIA_QUERY = `(max-width: ${IFRAME_BASE_WIDTH}px)`;
+
+function createIframe(t) {
+    const iframe = document.createElement("iframe");
+    iframe.srcdoc = "";
+    iframe.width = IFRAME_BASE_WIDTH;
+    iframe.height = "100";
+    iframe.style.border = "none";
+
+    t.add_cleanup(() => {
+        document.body.removeChild(iframe);
+    });
+
+    return new Promise(resolve => {
+        iframe.addEventListener("load", () => {
+            resolve(iframe);
+        });
+
+        document.body.appendChild(iframe);
+    });
+}
+
+function triggerMQLEvent(iframe) {
+    iframe.width = iframe.width === IFRAME_BASE_WIDTH ? "250" : IFRAME_BASE_WIDTH;
+}
+
+function waitForChangesReported() {
+    return new Promise(resolve => {
+        step_timeout(resolve, 75);
+    });
+}
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-load-event-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-load-event-expected.txt
deleted file mode 100644
index b8ee307..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-load-event-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-FAIL load event of blob URL assert_true: The iframe element should represent a nested browsing context. expected true got false
-FAIL load event of initial about:blank assert_true: The object element should represent a nested browsing context. expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-load-event.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-load-event.html
index d245bf0..5ffe53c 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-load-event.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-load-event.html
@@ -8,7 +8,7 @@
 async_test(function(t) {
   var obj = document.createElement("iframe");
   obj.onload = t.step_func_done(function(e){
-    assert_true(obj.contentWindow instanceof Window, "The iframe element should represent a nested browsing context.")
+    assert_not_equals(obj.contentWindow, null, "The iframe element should represent a nested browsing context.")
     assert_equals(Object.getPrototypeOf(e).constructor, Event, "The load event should use the Event interface.");
     assert_true(e.isTrusted, "The load event should be a trusted event.");
     assert_false(e.cancelable, "The load event should not be a cancelable event.");
@@ -16,9 +16,7 @@
     assert_equals(e.target, obj, "The load event target should be the corresponding object element.");
   });
 
-  obj.onerror = t.step_func_done(function(e){
-    assert_unreached("The error event should not be fired.");
-  });
+  obj.onerror = t.unreached_func("The error event should not be fired.");
 
   var url = URL.createObjectURL(new Blob([""], { type: "text/html" }));
 
@@ -29,7 +27,7 @@
 async_test(function(t) {
   var obj = document.createElement("iframe");
   obj.onload = t.step_func_done(function(e){
-    assert_true(obj.contentWindow instanceof Window, "The object element should represent a nested browsing context.")
+    assert_not_equals(obj.contentWindow, null, "The object element should represent a nested browsing context.")
     assert_equals(Object.getPrototypeOf(e).constructor, Event, "The load event should use the Event interface.");
     assert_true(e.isTrusted, "The load event should be a trusted event.");
     assert_false(e.cancelable, "The load event should not be a cancelable event.");
@@ -37,12 +35,9 @@
     assert_equals(e.target, obj, "The load event target should be the corresponding object element.");
   });
 
-  obj.onerror = t.step_func_done(function(e){
-    assert_unreached("The error event should not be fired.");
-  });
+  obj.onerror = t.unreached_func("The error event should not be fired.");
 
   document.body.appendChild(obj);
 }, "load event of initial about:blank");
-
 </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/firefox.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/firefox.py
index 781d7e31..6cf784f 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/firefox.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/firefox.py
@@ -198,7 +198,7 @@
 
 
 def update_properties():
-    return (["os", "debug", "webrender", "fisson", "e10s", "sw-e10s", "processor"],
+    return (["os", "debug", "webrender", "fission", "e10s", "sw-e10s", "processor"],
             {"os": ["version"], "processor": ["bits"]})
 
 
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader-document-hidden-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader-document-hidden-manual.https-expected.txt
new file mode 100644
index 0000000..9fba7c8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader-document-hidden-manual.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Test NFCReader.onreading is not fired when document is hidden assert_equals: Expected reading event, but got error event instead expected "reading" but got "error"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader-document-hidden-manual.https.html b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader-document-hidden-manual.https.html
new file mode 100644
index 0000000..6d9a52c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader-document-hidden-manual.https.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>NFCReader.onreading respect page visibility changes</title>
+<link rel="help" href="https://w3c.github.io/web-nfc/#visible-document">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+promise_test(async t => {
+  const reader = new NFCReader();
+  reader.scan();
+  const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]);
+
+  return await new Promise((resolve, reject) => {
+    readerWatcher.wait_for("reading").then(event => {
+      if (document.hidden) reject();
+      resolve();
+    });
+  });
+}, "Test NFCReader.onreading is not fired when document is hidden");
+
+</script>
+
+<p>Step1: switch the page to the background, then tap a formatted NFC tag.</p>
+<p>Step2: switch back to the page, then tap the tag again.</p>
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter-document-hidden-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter-document-hidden-manual.https-expected.txt
new file mode 100644
index 0000000..777243f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter-document-hidden-manual.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Test NFCWriter.push operation should be suspend when document is not visible promise_test: Unhandled rejection with value: undefined
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter-document-hidden-manual.https.html b/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter-document-hidden-manual.https.html
new file mode 100644
index 0000000..72d8c81
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter-document-hidden-manual.https.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>NFCWriter.push respect page visibility changes</title>
+<link rel="help" href="https://w3c.github.io/web-nfc/#visible-document">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/nfc-helpers.js"></script>
+<script>
+
+promise_test(async t => {
+  const writer = new NFCWriter();
+  const p1 = writer.push(test_text_data);
+
+  return await new Promise((resolve, reject) => {
+    p1.then(() => {
+      assert_false(document.hidden);
+      resolve();
+    }).catch(e => {
+      reject();
+    });
+  });
+}, "Test NFCWriter.push operation should be suspend when document is not visible");
+
+</script>
+
+<p>Step1: switch the page to the background, then tap an NFC tag.</p>
+<p>Step2: switch back to the page, then tap the tag again.</p>
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/element_click/bubbling.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/element_click/bubbling.py
index 2b08be1..a069a5a 100644
--- a/third_party/blink/web_tests/external/wpt/webdriver/tests/element_click/bubbling.py
+++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/element_click/bubbling.py
@@ -72,7 +72,7 @@
         for (var level = 0; level < elements.length; level++) {
           elements[level].addEventListener("click", function(clickEvent) {
             var target = clickEvent.currentTarget;
-            setTimeout(function() { window.delayedClicks.push(target); }, 100);
+            setTimeout(function() { window.delayedClicks.push(target); }, 0);
           });
         }
         </script>
diff --git a/third_party/private-join-and-compute/src/OWNERS b/third_party/private-join-and-compute/OWNERS
similarity index 100%
rename from third_party/private-join-and-compute/src/OWNERS
rename to third_party/private-join-and-compute/OWNERS
diff --git a/third_party/zlib/chromeconf.h b/third_party/zlib/chromeconf.h
index e9aa386..666093d 100644
--- a/third_party/zlib/chromeconf.h
+++ b/third_party/zlib/chromeconf.h
@@ -13,7 +13,7 @@
 #define ZEXTERN __declspec(dllimport)
 #endif
 #elif defined(ZLIB_IMPLEMENTATION)
-#define ZEXPORT __attribute__((visibility("default")))
+#define ZEXTERN __attribute__((visibility("default")))
 #endif
 #endif
 
diff --git a/tools/clang/blink_gc_plugin/OWNERS b/tools/clang/blink_gc_plugin/OWNERS
index 228cfbf..3bc99e6 100644
--- a/tools/clang/blink_gc_plugin/OWNERS
+++ b/tools/clang/blink_gc_plugin/OWNERS
@@ -1,3 +1,4 @@
+bikineev@chromium.org
 haraken@chromium.org
 kouhei@chromium.org
 mlippautz@chromium.org
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py
index dfba583..f3e047a 100755
--- a/tools/clang/scripts/build.py
+++ b/tools/clang/scripts/build.py
@@ -28,7 +28,6 @@
                     DownloadAndUnpack, EnsureDirExists, GetWinSDKDir,
                     ReadStampFile, RmTree, WriteStampFile)
 
-
 # Path constants. (All of these should be absolute paths.)
 THIRD_PARTY_DIR = os.path.join(CHROMIUM_DIR, 'third_party')
 LLVM_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm')
@@ -100,31 +99,31 @@
   modifications in dir will be lost."""
 
   print('Checking out LLVM monorepo %s into %s' % (commit, dir))
-  git_dir = os.path.join(dir, '.git')
-  fetch_cmd = ['git', '--git-dir', git_dir, 'fetch']
-  checkout_cmd = ['git', 'checkout', commit]
+
+  # Try updating the current repo if it exists and has no local diff.
+  if os.path.isdir(dir):
+    os.chdir(dir)
+    # git diff-index --quiet returns success when there is no diff.
+    if (RunCommand(['git', 'diff-index', '--quiet', 'HEAD'], fail_hard=False)
+        and RunCommand(['git', 'fetch'], fail_hard=False)
+        and RunCommand(['git', 'checkout', commit], fail_hard=False)):
+      return
+
+    # If we can't use the current repo, delete it.
+    os.chdir(CHROMIUM_DIR)  # Can't remove dir if we're in it.
+    print('Removing %s.' % dir)
+    RmTree(dir)
 
   # Do a somewhat shallow clone to save on bandwidth for GitHub and for us.
-  # The depth was whosen to be deep enough to contain the version we're
+  # The depth was chosen to be deep enough to contain the version we're
   # building, and shallow enough to save significantly on bandwidth compared to
   # a full clone.
   clone_cmd = ['git', 'clone', '--depth', '10000',
                'https://github.com/llvm/llvm-project/', dir]
 
-  # Try updating the current repo.
-  if RunCommand(fetch_cmd, fail_hard=False):
-    os.chdir(dir)
-    if RunCommand(checkout_cmd, fail_hard=False):
-      return
-
-  # Otherwise, do a fresh clone.
-  if os.path.isdir(dir):
-    os.chdir(CHROMIUM_DIR)  # Can't remove dir if we're in it.
-    print('Removing %s.' % dir)
-    RmTree(dir)
   if RunCommand(clone_cmd, fail_hard=False):
     os.chdir(dir)
-    if RunCommand(checkout_cmd, fail_hard=False):
+    if RunCommand(['git', 'checkout', commit], fail_hard=False):
       return
 
   print('CheckoutLLVM failed.')
diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py
index 6690343..5d7c1f9 100755
--- a/tools/clang/scripts/package.py
+++ b/tools/clang/scripts/package.py
@@ -178,15 +178,6 @@
     platform = 'Linux_x64'
 
   with open('buildlog.txt', 'w') as log:
-    if os.path.exists(LLVM_DIR):
-      Tee('Diff in llvm:\n', log)
-      cwd = os.getcwd()
-      os.chdir(LLVM_DIR)
-      TeeCmd(['git', 'status'], log, fail_hard=False)
-      TeeCmd(['git', 'diff'], log, fail_hard=False)
-      os.chdir(cwd)
-    else:
-      Tee('No previous llvm checkout.\n', log)
     Tee('Starting build\n', log)
 
     # Do a clobber build.
diff --git a/tools/gdb/gdbinit b/tools/gdb/gdbinit
index 78d3933..603206e8 100644
--- a/tools/gdb/gdbinit
+++ b/tools/gdb/gdbinit
@@ -9,7 +9,7 @@
 import sys
 
 compile_dirs = set()
-
+src_dir = None
 
 def get_current_debug_file_directories():
   dir = gdb.execute("show debug-file-directory", to_string=True)
@@ -47,6 +47,25 @@
   gdb.execute('source %s' % os.path.join(tools_gdb, 'viewg.gdb'))
 
 
+def set_src_dir(compile_dir):
+  global src_dir
+  git = subprocess.Popen(
+      ['git', '-C', compile_dir, 'rev-parse', '--show-toplevel'],
+      stdout=subprocess.PIPE,
+      stderr=subprocess.PIPE)
+  src_dir, _ = git.communicate()
+  if git.returncode:
+    return
+  if isinstance(src_dir, str):
+    src_dir = src_dir.rstrip()
+  else:
+    src_dir = src_dir.decode('utf-8').rstrip()
+
+  load_libcxx_pretty_printers(src_dir)
+
+  load_gdb_chrome(src_dir)
+
+
 def newobj_handler(event):
   global compile_dirs
   compile_dir = os.path.dirname(event.new_objfile.filename)
@@ -64,21 +83,9 @@
   # https://crbug.com/603286#c35
   add_debug_file_directory(compile_dir)
 
-  git = subprocess.Popen(
-      ['git', '-C', compile_dir, 'rev-parse', '--show-toplevel'],
-      stdout=subprocess.PIPE,
-      stderr=subprocess.PIPE)
-  src_dir, _ = git.communicate()
-  if git.returncode:
-    return
-  if isinstance(src_dir, str):
-    src_dir = src_dir.rstrip()
-  else:
-    src_dir = src_dir.decode('utf-8').rstrip()
-
-  load_libcxx_pretty_printers(src_dir)
-
-  load_gdb_chrome(src_dir)
+  global src_dir
+  if not src_dir:
+    set_src_dir(compile_dir)
 
 
 # Event hook for newly loaded objfiles.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 814349f..fb18a8d 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -4681,6 +4681,7 @@
   <int value="8" label="MissingPersonalCurve"/>
   <int value="9" label="WaitingForTrainedPersonalCurve"/>
   <int value="10" label="WaitingForReopenAls"/>
+  <int value="11" label="NoNewModel"/>
 </enum>
 
 <enum name="AutoScreenBrightnessParameterError">
@@ -6979,6 +6980,11 @@
   <int value="1" label="Visible"/>
 </enum>
 
+<enum name="BooleanVolumeZero">
+  <int value="0" label="Not zero"/>
+  <int value="1" label="Zero"/>
+</enum>
+
 <enum name="BooleanWaited">
   <int value="0" label="Did not wait"/>
   <int value="1" label="Waited"/>
@@ -36716,6 +36722,7 @@
   <int value="36422284"
       label="AutofillSaveCardDialogUnlabeledExpirationDate:enabled"/>
   <int value="37024318" label="disable-affiliation-based-matching"/>
+  <int value="38213894" label="PrivacySettingsRedesign:enabled"/>
   <int value="38904620" label="TabSwitcherLongpressMenu:enabled"/>
   <int value="42098736" label="TranslateAndroidManualTrigger:disabled"/>
   <int value="42844603" label="AndroidSurfaceControl:disabled"/>
@@ -37600,6 +37607,7 @@
   <int value="1247293682" label="topchrome-md"/>
   <int value="1250071868" label="disable-timezone-tracking-option"/>
   <int value="1253698118" label="ash-disable-stable-overview-order"/>
+  <int value="1254472299" label="PrivacySettingsRedesign:disabled"/>
   <int value="1257482622" label="PageAlmostIdle:enabled"/>
   <int value="1257533754" label="UseDownloadOfflineContentProvider:disabled"/>
   <int value="1257980502" label="disable-accelerated-video-decode"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 3b86b14..01b45a6 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -12932,6 +12932,12 @@
   </summary>
 </histogram>
 
+<histogram name="AutoScreenBrightness.GlobalCurveResetOnInitialization"
+    enum="Boolean" expires_after="2020-03-01">
+  <owner>jiameng@chromium.org</owner>
+  <summary>Whether the global curve is reset at initialization.</summary>
+</histogram>
+
 <histogram name="AutoScreenBrightness.MissingAlsWhenBrightnessChanged"
     enum="BooleanError" expires_after="2020-03-01">
   <owner>jiameng@chromium.org</owner>
@@ -25542,7 +25548,7 @@
   </summary>
 </histogram>
 
-<histogram name="Cras.InputDeviceAbnormalFallback" units="seconds"
+<histogram name="Cras.InputDeviceAbnormalFallbackRuntime" units="seconds"
     expires_after="2020-10-03">
   <owner>yuhsuan@chromium.org</owner>
   <owner>chromeos-audio@google.com</owner>
@@ -25652,7 +25658,7 @@
   </summary>
 </histogram>
 
-<histogram name="Cras.InputDeviceNormalFallback" units="seconds"
+<histogram name="Cras.InputDeviceNormalFallbackRuntime" units="seconds"
     expires_after="2020-10-03">
   <owner>yuhsuan@chromium.org</owner>
   <owner>chromeos-audio@google.com</owner>
@@ -25696,7 +25702,7 @@
   </summary>
 </histogram>
 
-<histogram name="Cras.InputDeviceSilentHotword" units="seconds"
+<histogram name="Cras.InputDeviceSilentHotwordRuntime" units="seconds"
     expires_after="2020-10-03">
   <owner>yuhsuan@chromium.org</owner>
   <owner>chromeos-audio@google.com</owner>
@@ -25835,6 +25841,17 @@
   </summary>
 </histogram>
 
+<histogram name="Cras.OutputDeviceAbnormalFallbackRuntime" units="seconds"
+    expires_after="2020-10-03">
+  <owner>yuhsuan@chromium.org</owner>
+  <owner>chromeos-audio@google.com</owner>
+  <summary>
+    The runtime of fallback device in the abnormal situation. The runtime is the
+    duration between opening and closing a device. The value is recorded when
+    the device is closed.
+  </summary>
+</histogram>
+
 <histogram name="Cras.OutputDeviceBluetoothRuntime" units="seconds"
     expires_after="2020-05-13">
   <owner>yuhsuan@chromium.org</owner>
@@ -25923,6 +25940,17 @@
   </summary>
 </histogram>
 
+<histogram name="Cras.OutputDeviceNormalFallbackRuntime" units="seconds"
+    expires_after="2020-10-03">
+  <owner>yuhsuan@chromium.org</owner>
+  <owner>chromeos-audio@google.com</owner>
+  <summary>
+    The runtime of fallback device in the normal situation. The runtime is the
+    duration between opening and closing a device. The value is recorded when
+    the device is closed.
+  </summary>
+</histogram>
+
 <histogram name="Cras.OutputDeviceUnknownRuntime" units="seconds"
     expires_after="2020-05-13">
   <owner>yuhsuan@chromium.org</owner>
@@ -60302,6 +60330,17 @@
   </summary>
 </histogram>
 
+<histogram name="Media.Audio.InputVolumeStartsAtZeroWin"
+    enum="BooleanVolumeZero" expires_after="2020-10-15">
+  <owner>henrika@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    Indicates if the volume level of the audio session is set to zero when the
+    input audio session starts. Sampled once when the stream starts but only on
+    Windows platforms. See http://crbug.com/1014443.
+  </summary>
+</histogram>
+
 <histogram name="Media.Audio.IsOnBatteryPowerMac" enum="BooleanOnBattery"
     expires_after="2018-08-22">
   <obsolete>
diff --git a/tools/perf/core/results_processor/compute_metrics.py b/tools/perf/core/results_processor/compute_metrics.py
index 4625ef0..6cb31ca 100644
--- a/tools/perf/core/results_processor/compute_metrics.py
+++ b/tools/perf/core/results_processor/compute_metrics.py
@@ -60,8 +60,9 @@
   """Compute metrics on aggregated traces in parallel.
 
   For each test run that has an aggregate trace and some TBMv2 metrics listed
-  in its tags, compute the metrics and store the result as histogram dicts
-  in the corresponding test result.
+  in its tags, compute the metrics and return the list of all resulting
+  histograms. Note: the order of histograms in the results may be different
+  from the order of tests in intermediate_results.
   """
   histogram_dicts = []
   work_list = []
diff --git a/tools/perf/core/results_processor/formatters/json3_output.py b/tools/perf/core/results_processor/formatters/json3_output.py
index 8294758..96b144c 100644
--- a/tools/perf/core/results_processor/formatters/json3_output.py
+++ b/tools/perf/core/results_processor/formatters/json3_output.py
@@ -8,13 +8,13 @@
 https://chromium.googlesource.com/chromium/src/+/master/docs/testing/json_test_results_format.md
 """
 
-import calendar
 import collections
-import datetime
 import json
 import os
 import urllib
 
+from core.results_processor import util
+
 
 OUTPUT_FILENAME = 'test-results.json'
 
@@ -79,7 +79,7 @@
 
   benchmark_run = in_results['benchmarkRun']
   results.update(
-      seconds_since_epoch=_TimestampToEpoch(benchmark_run['startTime']),
+      seconds_since_epoch=util.IsoTimestampToEpoch(benchmark_run['startTime']),
       interrupted=benchmark_run['interrupted'],
       num_failures_by_type=dict(status_counter),
       path_delimiter='/',
@@ -122,12 +122,6 @@
     return path.replace(os.sep, '/')
 
 
-def _TimestampToEpoch(timestamp):
-  """Convert UTC timestamp to seconds since epoch with microsecond precision."""
-  dt = datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%fZ')
-  return calendar.timegm(dt.timetuple()) + dt.microsecond / 1e6
-
-
 def _MergeDict(target, values):
   # Is used to merge multiple runs of a story into a single test result.
   for key, value in values.items():
diff --git a/tools/perf/core/results_processor/processor.py b/tools/perf/core/results_processor/processor.py
index 4e22cd5f..b72e208 100644
--- a/tools/perf/core/results_processor/processor.py
+++ b/tools/perf/core/results_processor/processor.py
@@ -21,11 +21,15 @@
 from core.results_processor import util
 
 from tracing.trace_data import trace_data
+from tracing.value.diagnostics import date_range
 from tracing.value.diagnostics import generic_set
 from tracing.value.diagnostics import reserved_infos
+from tracing.value import histogram
 from tracing.value import histogram_set
+from tracing.value import legacy_unit_info
 
 TELEMETRY_RESULTS = '_telemetry_results.jsonl'
+MEASUREMENTS_NAME = 'measurements.json'
 
 FORMATS_WITH_METRICS = ['csv', 'histograms', 'html']
 
@@ -92,10 +96,6 @@
         results['benchmarkRun'].update(record['benchmarkRun'])
       if 'testResult' in record:
         test_result = record['testResult']
-        # TODO(crbug.com/1011813): This is for compatibility with old version
-        # of LUCI format. Remove it when Telemetry switches to a new version.
-        if 'artifacts' in test_result:
-          test_result['outputArtifacts'] = test_result.pop('artifacts')
         results['testResults'].append(test_result)
   return results
 
@@ -179,6 +179,7 @@
 
 def _ComputeMetrics(intermediate_results, results_label):
   histogram_dicts = compute_metrics.ComputeTBMv2Metrics(intermediate_results)
+  histogram_dicts += ExtractMeasurements(intermediate_results)
   histogram_dicts = AddDiagnosticsToHistograms(
       histogram_dicts, intermediate_results, results_label)
   return histogram_dicts
@@ -202,6 +203,68 @@
         reserved_infos.LABELS.name,
         generic_set.GenericSet([results_label]))
 
+  histograms.DeduplicateDiagnostics()
+  return histograms.AsDicts()
+
+
+def MeasurementToHistogram(name, measurement):
+  unit = measurement['unit']
+  samples = measurement['samples']
+  description = measurement.get('description')
+  if unit in legacy_unit_info.LEGACY_UNIT_INFO:
+    info = legacy_unit_info.LEGACY_UNIT_INFO[unit]
+    unit = info.name
+    samples = [s * info.conversion_factor for s in samples]
+  if unit not in histogram.UNIT_NAMES:
+    raise ValueError('Unknown unit: %s' % unit)
+  return histogram.Histogram.Create(name, unit, samples,
+                                    description=description)
+
+
+def _GlobalDiagnostics(benchmark_run):
+  """Extract diagnostics information about the whole benchmark run.
+
+  These diagnostics will be added to ad-hoc measurements recorded by
+  benchmarks.
+  """
+  timestamp_ms = util.IsoTimestampToEpoch(benchmark_run['startTime']) * 1e3
+  return {
+    reserved_infos.BENCHMARK_START.name: date_range.DateRange(timestamp_ms),
+  }
+
+
+def _StoryDiagnostics(test_result):
+  """Extract diagnostics information about the specific story.
+
+  These diagnostics will be added to ad-hoc measurements recorded by
+  benchmarks.
+  """
+  benchmark_name, story_name = test_result['testPath'].split('/', 1)
+  story_tags = [tag['value'] for tag in test_result.get('tags', [])
+                if tag['key'] == 'story_tag']
+  return {
+      reserved_infos.BENCHMARKS.name: generic_set.GenericSet([benchmark_name]),
+      reserved_infos.STORIES.name: generic_set.GenericSet([story_name]),
+      reserved_infos.STORY_TAGS.name: generic_set.GenericSet(story_tags),
+  }
+
+
+def ExtractMeasurements(intermediate_results):
+  """Add ad-hoc measurements to histogram dicts"""
+  histograms = histogram_set.HistogramSet()
+  global_diagnostics = _GlobalDiagnostics(intermediate_results['benchmarkRun'])
+
+  for result in intermediate_results['testResults']:
+    artifacts = result.get('outputArtifacts', {})
+    if MEASUREMENTS_NAME in artifacts:
+      with open(artifacts[MEASUREMENTS_NAME]['filePath']) as f:
+        measurements = json.load(f)['measurements']
+      diagnostics = global_diagnostics.copy()
+      diagnostics.update(_StoryDiagnostics(result))
+      for name, measurement in measurements.iteritems():
+        histograms.AddHistogram(MeasurementToHistogram(name, measurement),
+                                diagnostics=diagnostics)
+
   return histograms.AsDicts()
 
 
diff --git a/tools/perf/core/results_processor/processor_test.py b/tools/perf/core/results_processor/processor_test.py
index b25893d4..900de29 100644
--- a/tools/perf/core/results_processor/processor_test.py
+++ b/tools/perf/core/results_processor/processor_test.py
@@ -10,6 +10,7 @@
 """
 
 import csv
+import datetime
 import json
 import os
 import shutil
@@ -25,6 +26,7 @@
 from core.results_processor import testing
 
 from tracing.value.diagnostics import generic_set
+from tracing.value.diagnostics import date_range
 from tracing.value import histogram
 from tracing.value import histogram_set
 from tracing_build import render_histograms_viewer
@@ -309,6 +311,73 @@
     self.assertIsNotNone(hist)
     self.assertIn('traceUrls', hist.diagnostics)
 
+  def testHistogramsOutputMeasurements(self):
+    measure_file = os.path.join(self.output_dir,
+                                processor.MEASUREMENTS_NAME)
+    with open(measure_file, 'w') as f:
+      json.dump({'measurements': {
+          'a': {'unit': 'ms', 'samples': [4, 6], 'description': 'desc_a'},
+          'b': {'unit': 'ms', 'samples': [5], 'description': 'desc_b'},
+      }}, f)
+
+    start_ts = 1500000000
+    start_iso = datetime.datetime.utcfromtimestamp(start_ts).isoformat() + 'Z'
+
+    self.SerializeIntermediateResults(
+        test_results=[
+            testing.TestResult(
+                'benchmark/story',
+                output_artifacts={
+                    processor.MEASUREMENTS_NAME: testing.Artifact(measure_file)
+                },
+                tags=['story_tag:test']
+            ),
+        ],
+        start_time=start_iso,
+    )
+
+    processor.main([
+        '--output-format', 'histograms',
+        '--output-dir', self.output_dir,
+        '--intermediate-dir', self.intermediate_dir,
+    ])
+
+    with open(os.path.join(
+        self.output_dir, histograms_output.OUTPUT_FILENAME)) as f:
+      results = json.load(f)
+
+    out_histograms = histogram_set.HistogramSet()
+    out_histograms.ImportDicts(results)
+    self.assertEqual(len(out_histograms), 2)
+
+    hist = out_histograms.GetHistogramNamed('a')
+    self.assertEqual(hist.name, 'a')
+    self.assertEqual(hist.unit, 'ms_smallerIsBetter')
+    self.assertEqual(hist.sample_values, [4, 6])
+    self.assertEqual(hist.description, 'desc_a')
+    self.assertEqual(hist.diagnostics['benchmarks'],
+                     generic_set.GenericSet(['benchmark']))
+    self.assertEqual(hist.diagnostics['stories'],
+                     generic_set.GenericSet(['story']))
+    self.assertEqual(hist.diagnostics['storyTags'],
+                     generic_set.GenericSet(['test']))
+    self.assertEqual(hist.diagnostics['benchmarkStart'],
+                     date_range.DateRange(start_ts * 1e3))
+
+    hist = out_histograms.GetHistogramNamed('b')
+    self.assertEqual(hist.name, 'b')
+    self.assertEqual(hist.unit, 'ms_smallerIsBetter')
+    self.assertEqual(hist.sample_values, [5])
+    self.assertEqual(hist.description, 'desc_b')
+    self.assertEqual(hist.diagnostics['benchmarks'],
+                     generic_set.GenericSet(['benchmark']))
+    self.assertEqual(hist.diagnostics['stories'],
+                     generic_set.GenericSet(['story']))
+    self.assertEqual(hist.diagnostics['storyTags'],
+                     generic_set.GenericSet(['test']))
+    self.assertEqual(hist.diagnostics['benchmarkStart'],
+                     date_range.DateRange(start_ts * 1e3))
+
   def testHtmlOutput(self):
     hist_file = os.path.join(self.output_dir,
                              compute_metrics.HISTOGRAM_DICTS_FILE)
diff --git a/tools/perf/core/results_processor/processor_unittest.py b/tools/perf/core/results_processor/processor_unittest.py
index 8878f0f4..c68a1ed 100644
--- a/tools/perf/core/results_processor/processor_unittest.py
+++ b/tools/perf/core/results_processor/processor_unittest.py
@@ -147,3 +147,29 @@
       artifacts = result['outputArtifacts']
       self.assertEqual(len(artifacts), 1)
       self.assertEqual(artifacts.keys()[0], 'trace.html')
+
+  def testMeasurementToHistogram(self):
+    hist = processor.MeasurementToHistogram('a', {
+      'unit': 'sizeInBytes',
+      'samples': [1, 2, 3],
+      'description': 'desc',
+    })
+
+    self.assertEqual(hist.name, 'a')
+    self.assertEqual(hist.unit, 'sizeInBytes')
+    self.assertEqual(hist.sample_values, [1, 2, 3])
+    self.assertEqual(hist.description, 'desc')
+
+  def testMeasurementToHistogramLegacyUnits(self):
+    hist = processor.MeasurementToHistogram('a', {
+      'unit': 'seconds',
+      'samples': [1, 2, 3],
+    })
+
+    self.assertEqual(hist.name, 'a')
+    self.assertEqual(hist.unit, 'ms_smallerIsBetter')
+    self.assertEqual(hist.sample_values, [1000, 2000, 3000])
+
+  def testMeasurementToHistogramUnknownUnits(self):
+    with self.assertRaises(ValueError):
+      processor.MeasurementToHistogram('a', {'unit': 'yards', 'samples': [9]})
diff --git a/tools/perf/core/results_processor/util.py b/tools/perf/core/results_processor/util.py
index 2bbe332..3425c46 100644
--- a/tools/perf/core/results_processor/util.py
+++ b/tools/perf/core/results_processor/util.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import calendar
+import datetime
 import logging
 import multiprocessing
 from multiprocessing.dummy import Pool as ThreadPool
@@ -48,3 +50,12 @@
     pool.join()
   finally:
     pool.terminate()
+
+
+def IsoTimestampToEpoch(timestamp):
+  """Convert ISO formatted time to seconds since epoch."""
+  try:
+    dt = datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%fZ')
+  except ValueError:
+    dt = datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%SZ')
+  return calendar.timegm(dt.timetuple()) + dt.microsecond / 1e6
diff --git a/ui/display/util/edid_parser.cc b/ui/display/util/edid_parser.cc
index 44f2fdb..1adebb7 100644
--- a/ui/display/util/edid_parser.cc
+++ b/ui/display/util/edid_parser.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 
 #include <algorithm>
+#include <bitset>
 
 #include "base/hash/hash.h"
 #include "base/strings/string_util.h"
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_impl.js b/ui/file_manager/file_manager/background/js/volume_manager_impl.js
index 52e76153..616e7514 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_impl.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager_impl.js
@@ -125,14 +125,14 @@
     chrome.fileManagerPrivate.onMountCompleted.addListener(
         this.onMountCompleted_.bind(this));
 
-    console.warn('Getting volumes');
+    console.debug('Getting volumes');
     const volumeMetadataList = await new Promise(
         resolve => chrome.fileManagerPrivate.getVolumeMetadataList(resolve));
     if (!volumeMetadataList) {
       console.error('Cannot get volumes');
       return;
     }
-    console.warn(`There are ${volumeMetadataList.length} volumes`);
+    console.debug(`There are ${volumeMetadataList.length} volumes`);
 
     // We must subscribe to the mount completed event in the callback of
     // getVolumeMetadataList (crbug.com/330061). But volumes reported by
@@ -142,12 +142,12 @@
     try {
       // Create VolumeInfo for each volume.
       await Promise.all(volumeMetadataList.map(async (volumeMetadata) => {
-        console.warn(`Initializing volume '${volumeMetadata.volumeId}'`);
+        console.debug(`Initializing volume '${volumeMetadata.volumeId}'`);
         const volumeInfo = await this.addVolumeMetadata_(volumeMetadata);
-        console.warn(`Initialized volume '${volumeInfo.volumeId}'`);
+        console.debug(`Initialized volume '${volumeInfo.volumeId}'`);
       }));
 
-      console.warn(`Initialized all ${volumeMetadataList.length} volumes`);
+      console.debug(`Initialized all ${volumeMetadataList.length} volumes`);
     } finally {
       unlock();
     }
@@ -172,7 +172,7 @@
             case 'success':
             case VolumeManagerCommon.VolumeError.UNKNOWN_FILESYSTEM:
             case VolumeManagerCommon.VolumeError.UNSUPPORTED_FILESYSTEM: {
-              console.warn(`Mounted '${sourcePath}' as '${volumeId}'`);
+              console.debug(`Mounted '${sourcePath}' as '${volumeId}'`);
               const volumeInfo = await this.addVolumeMetadata_(volumeMetadata);
               this.finishRequest_(requestKey, status, volumeInfo);
               return;
@@ -211,7 +211,7 @@
                 this.dispatchEvent(new CustomEvent(
                     'externally-unmounted', {detail: volumeInfo}));
               } else {
-                console.warn(`Unmounted '${volumeId}'`);
+                console.debug(`Unmounted '${volumeId}'`);
               }
 
               this.volumeInfoList.remove(volumeId);
@@ -249,7 +249,7 @@
     const path = await new Promise(resolve => {
       chrome.fileManagerPrivate.addMount(fileUrl, resolve);
     });
-    console.warn(`Mounting '${path}'`);
+    console.debug(`Mounting '${path}'`);
     const key = this.makeRequestKey_('mount', path);
     return this.startRequest_(key);
   }
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_util.js b/ui/file_manager/file_manager/background/js/volume_manager_util.js
index d298cf0..21092c02 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_util.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager_util.js
@@ -93,7 +93,7 @@
       break;
   }
 
-  console.warn(`Getting file system '${volumeMetadata.volumeId}'`);
+  console.debug(`Getting file system '${volumeMetadata.volumeId}'`);
   return util
       .timeoutPromise(
           new Promise((resolve, reject) => {
@@ -139,7 +139,7 @@
       .then(
           /** @param {!FileSystem} fileSystem */
           fileSystem => {
-            console.warn(`Got file system '${volumeMetadata.volumeId}'`);
+            console.debug(`Got file system '${volumeMetadata.volumeId}'`);
             if (volumeMetadata.volumeType ===
                 VolumeManagerCommon.VolumeType.DRIVE) {
               // After file system is mounted, we "read" drive grand root
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index ebe1e5df..64a7ddc9 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -625,9 +625,7 @@
     this.ui_.decorateFilesMenuItems();
     this.ui_.selectionMenuButton.hidden = false;
 
-    console.warn('Files app sync started');
     await Promise.all([fileListPromise, currentDirectoryPromise]);
-    console.warn('Files app sync finished');
   }
 
   /**
@@ -776,7 +774,6 @@
   initGeneral_() {
     // Initialize the application state.
     // TODO(mtomasz): Unify window.appState with location.search format.
-    console.warn('Files app starting up');
     if (window.appState) {
       const params = {};
 
@@ -1402,8 +1399,6 @@
     const promise = (async () => {
       if (directoryEntry) {
         const entryDescription = util.entryDebugString(directoryEntry);
-        console.warn(
-            `Files app start up: Changing to directory: ${entryDescription}`);
         await new Promise(resolve => {
           this.directoryModel_.changeDirectoryEntry(
               assert(directoryEntry), resolve);
@@ -1411,8 +1406,6 @@
         if (opt_selectionEntry) {
           this.directoryModel_.selectEntry(opt_selectionEntry);
         }
-        console.warn(
-            `Files app start up: Changed to directory: ${entryDescription}`);
       } else {
         console.warn('No entry for finishSetupCurrentDirectory_');
       }
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd
index dfc1218..3c290930 100644
--- a/ui/strings/ui_strings.grd
+++ b/ui/strings/ui_strings.grd
@@ -974,6 +974,9 @@
       <message name="IDS_BROWSER_SHARING_DIALOG_DEVICE_SUBTITLE_LAST_ACTIVE_DAYS" desc="The label to be shown below the name of a valid device indicating the last active time of device,">
         {DAYS, plural, =0 {Active today} =1 {Active 1 day ago} other {Active # days ago}}
       </message>
+      <message name="IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_INITIATING_ORIGIN" desc="The label for the initiating origin shown in Click to Call dialogs.">
+        Number initiated from <ph name="ORIGIN">$1<ex>https://google.com</ex></ph>
+      </message>
 
       <!-- Sharing content types -->
       <message name="IDS_BROWSER_SHARING_CONTENT_TYPE_TEXT" desc="The label used to describe that the content type being shared is a text.">
diff --git a/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_INITIATING_ORIGIN.png.sha1 b/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_INITIATING_ORIGIN.png.sha1
new file mode 100644
index 0000000..f47def1
--- /dev/null
+++ b/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_INITIATING_ORIGIN.png.sha1
@@ -0,0 +1 @@
+13c78c8e166977023ad414654032cb20c3b394ed
\ No newline at end of file
diff --git a/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc b/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
index 960a65a3..28b2e76b 100644
--- a/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
+++ b/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
@@ -395,7 +395,7 @@
   bubble_frame->ResetWindowControls();
   bubble_frame->Layout();
 
-  Button* close_button = bubble_frame->GetCloseButtonForTest();
+  Button* close_button = bubble_frame->GetCloseButtonForTesting();
   // Title moves over for the close button.
   EXPECT_EQ(close_button->x() - LayoutProvider::Get()->GetDistanceMetric(
                                     DISTANCE_CLOSE_BUTTON_MARGIN),
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc
index 3282d72..40e3408 100644
--- a/ui/views/bubble/bubble_frame_view.cc
+++ b/ui/views/bubble/bubble_frame_view.cc
@@ -338,14 +338,11 @@
   bounds.Inset(title_margins_);
 
   int header_bottom = 0;
-  gfx::Size header_pref_size = GetHeaderSize();
-  if (!header_pref_size.IsEmpty()) {
-    int header_width = header_pref_size.width();
-    int header_offset = (contents_bounds.width() - header_width) / 2;
-    header_view_->SetBounds(contents_bounds.x() + header_offset,
-                            contents_bounds.y(), header_pref_size.width(),
-                            header_pref_size.height());
-    bounds.Inset(0, header_pref_size.height(), 0, 0);
+  int header_height = GetHeaderHeightForFrameWidth(contents_bounds.width());
+  if (header_height > 0) {
+    header_view_->SetBounds(contents_bounds.x(), contents_bounds.y(),
+                            contents_bounds.width(), header_height);
+    bounds.Inset(0, header_height, 0, 0);
     header_bottom = header_view_->bounds().bottom();
   }
 
@@ -712,7 +709,7 @@
 }
 
 gfx::Insets BubbleFrameView::GetTitleLabelInsetsFromFrame() const {
-  int header_height = GetHeaderSize().height();
+  int header_height = GetHeaderHeightForFrameWidth(GetContentsBounds().width());
   int insets_right = 0;
   if (GetWidget()->widget_delegate()->ShouldShowCloseButton()) {
     const int close_margin =
@@ -739,7 +736,7 @@
 
 gfx::Insets BubbleFrameView::GetClientInsetsForFrameWidth(
     int frame_width) const {
-  int header_height = GetHeaderSize().height();
+  int header_height = GetHeaderHeightForFrameWidth(frame_width);
   int close_height = 0;
   if (!ExtendClientIntoTitle() &&
       GetWidget()->widget_delegate()->ShouldShowCloseButton()) {
@@ -764,10 +761,10 @@
                      0);
 }
 
-gfx::Size BubbleFrameView::GetHeaderSize() const {
+int BubbleFrameView::GetHeaderHeightForFrameWidth(int frame_width) const {
   return header_view_ && header_view_->GetVisible()
-             ? header_view_->GetPreferredSize()
-             : gfx::Size();
+             ? header_view_->GetHeightForWidth(frame_width)
+             : 0;
 }
 
 }  // namespace views
diff --git a/ui/views/bubble/bubble_frame_view.h b/ui/views/bubble/bubble_frame_view.h
index 66c8fb57..f94f4a7 100644
--- a/ui/views/bubble/bubble_frame_view.h
+++ b/ui/views/bubble/bubble_frame_view.h
@@ -146,7 +146,9 @@
                                    const gfx::Size& client_size,
                                    bool adjust_to_fit_available_bounds);
 
-  Button* GetCloseButtonForTest() { return close_; }
+  Button* GetCloseButtonForTesting() { return close_; }
+
+  View* GetHeaderViewForTesting() const { return header_view_; }
 
   // Resets the time when view has been shown. Tests may need to call this
   // method if they use events that could be otherwise treated as unintended.
@@ -213,9 +215,9 @@
   // The client_view insets (from the frame view) for the given |frame_width|.
   gfx::Insets GetClientInsetsForFrameWidth(int frame_width) const;
 
-  // Gets the size of the |header_view_| or an empty size if there is no header
-  // view or if it is not visible.
-  gfx::Size GetHeaderSize() const;
+  // Gets the height of the |header_view_| given a |frame_width|. Returns zero
+  // if there is no header view or if it is not visible.
+  int GetHeaderHeightForFrameWidth(int frame_width) const;
 
   // The bubble border.
   BubbleBorder* bubble_border_ = nullptr;
diff --git a/ui/views/bubble/bubble_frame_view_unittest.cc b/ui/views/bubble/bubble_frame_view_unittest.cc
index c5622c6..c95bbc6 100644
--- a/ui/views/bubble/bubble_frame_view_unittest.cc
+++ b/ui/views/bubble/bubble_frame_view_unittest.cc
@@ -166,7 +166,7 @@
   const gfx::Insets content_margins = frame.content_margins();
   const gfx::Insets insets = frame.GetBorderInsets();
   const int close_margin =
-      frame.GetCloseButtonForTest()->height() +
+      frame.GetCloseButtonForTesting()->height() +
       LayoutProvider::Get()->GetDistanceMetric(DISTANCE_CLOSE_BUTTON_MARGIN);
   const gfx::Rect client_view_bounds = frame.GetBoundsForClientView();
   EXPECT_EQ(insets.left() + content_margins.left(), client_view_bounds.x());
@@ -877,7 +877,7 @@
   frame.widget_delegate()->SetShouldShowCloseButton(true);
 
   const int close_margin =
-      frame.GetCloseButtonForTest()->height() +
+      frame.GetCloseButtonForTesting()->height() +
       LayoutProvider::Get()->GetDistanceMetric(DISTANCE_CLOSE_BUTTON_MARGIN);
   const gfx::Insets content_margins = frame.content_margins();
   const gfx::Insets insets = frame.GetBorderInsets();
@@ -1127,7 +1127,7 @@
 
   BubbleFrameView* frame = delegate.GetBubbleFrameView();
   const int close_margin =
-      frame->GetCloseButtonForTest()->height() +
+      frame->GetCloseButtonForTesting()->height() +
       LayoutProvider::Get()->GetDistanceMetric(DISTANCE_CLOSE_BUTTON_MARGIN);
 
   // Set a header view that is 1 dip smaller smaller than the close button.
diff --git a/ui/views/test/ui_controls_factory_desktop_aurax11.cc b/ui/views/test/ui_controls_factory_desktop_aurax11.cc
index a258860..6e69e40 100644
--- a/ui/views/test/ui_controls_factory_desktop_aurax11.cc
+++ b/ui/views/test/ui_controls_factory_desktop_aurax11.cc
@@ -251,10 +251,10 @@
     // Most interactive_ui_tests run inside of the aura_test_helper
     // environment. This means that we can't rely on display::Screen and several
     // other things to work properly. Therefore we hack around this by
-    // iterating across the windows owned DesktopWindowTreeHostX11 since this
+    // iterating across the windows owned DesktopWindowTreeHostLinux since this
     // doesn't rely on having a DesktopScreenX11.
     std::vector<aura::Window*> windows =
-        DesktopWindowTreeHostX11::GetAllOpenWindows();
+        DesktopWindowTreeHostLinux::GetAllOpenWindows();
     const auto i =
         std::find_if(windows.cbegin(), windows.cend(), [point](auto* window) {
           return window->GetBoundsInScreen().Contains(point) ||
diff --git a/ui/views/test/widget_test_aura.cc b/ui/views/test/widget_test_aura.cc
index e1d6b9b8..0ae91d8f 100644
--- a/ui/views/test/widget_test_aura.cc
+++ b/ui/views/test/widget_test_aura.cc
@@ -13,10 +13,13 @@
 #include "ui/views/widget/widget.h"
 #include "ui/wm/core/shadow_controller.h"
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
+#endif
+
 #if defined(USE_X11)
 #include "ui/gfx/x/x11.h"        // nogncheck
 #include "ui/gfx/x/x11_types.h"  // nogncheck
-#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
 #endif
 
 namespace views {
@@ -69,8 +72,8 @@
 
 std::vector<aura::Window*> GetAllTopLevelWindows() {
   std::vector<aura::Window*> roots;
-#if defined(USE_X11)
-  roots = DesktopWindowTreeHostX11::GetAllOpenWindows();
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+  roots = DesktopWindowTreeHostLinux::GetAllOpenWindows();
 #elif defined(OS_WIN)
   {
     FindAllWindowsData data = {&roots};
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
index a4e8174..6ca1be4 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -118,8 +118,8 @@
   // aura::Window's screen bounds.
   aura::WindowTreeHost* host = window->GetHost();
   if (host) {
-    DesktopWindowTreeHostX11* rwh =
-        DesktopWindowTreeHostX11::GetHostForXID(host->GetAcceleratedWidget());
+    auto* rwh = DesktopWindowTreeHostLinux::GetHostForWidget(
+        host->GetAcceleratedWidget());
     if (rwh) {
       const gfx::Rect pixel_rect = rwh->GetBoundsInPixels();
       const gfx::Rect dip_rect =
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
index 62e8913..4f888a1 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
@@ -19,8 +19,17 @@
 #include "ui/views/widget/desktop_aura/window_event_filter_linux.h"
 #include "ui/views/widget/widget.h"
 
+DEFINE_UI_CLASS_PROPERTY_TYPE(views::DesktopWindowTreeHostLinux*)
+
 namespace views {
 
+std::list<gfx::AcceleratedWidget>* DesktopWindowTreeHostLinux::open_windows_ =
+    nullptr;
+
+DEFINE_UI_CLASS_PROPERTY_KEY(DesktopWindowTreeHostLinux*,
+                             kHostForRootWindow,
+                             nullptr)
+
 namespace {
 
 class SwapWithNewSizeObserverHelper : public ui::CompositorObserver {
@@ -63,7 +72,48 @@
     : DesktopWindowTreeHostPlatform(native_widget_delegate,
                                     desktop_native_widget_aura) {}
 
-DesktopWindowTreeHostLinux::~DesktopWindowTreeHostLinux() = default;
+DesktopWindowTreeHostLinux::~DesktopWindowTreeHostLinux() {
+  window()->ClearProperty(kHostForRootWindow);
+}
+
+// static
+aura::Window* DesktopWindowTreeHostLinux::GetContentWindowForWidget(
+    gfx::AcceleratedWidget widget) {
+  auto* host = DesktopWindowTreeHostLinux::GetHostForWidget(widget);
+  return host ? host->GetContentWindow() : nullptr;
+}
+
+// static
+DesktopWindowTreeHostLinux* DesktopWindowTreeHostLinux::GetHostForWidget(
+    gfx::AcceleratedWidget widget) {
+  aura::WindowTreeHost* host =
+      aura::WindowTreeHost::GetForAcceleratedWidget(widget);
+  return host ? host->window()->GetProperty(kHostForRootWindow) : nullptr;
+}
+
+// static
+std::vector<aura::Window*> DesktopWindowTreeHostLinux::GetAllOpenWindows() {
+  std::vector<aura::Window*> windows(open_windows().size());
+  std::transform(open_windows().begin(), open_windows().end(), windows.begin(),
+                 GetContentWindowForWidget);
+  return windows;
+}
+
+// static
+void DesktopWindowTreeHostLinux::CleanUpWindowList(
+    void (*func)(aura::Window* window)) {
+  if (!open_windows_)
+    return;
+  while (!open_windows_->empty()) {
+    gfx::AcceleratedWidget widget = open_windows_->front();
+    func(GetContentWindowForWidget(widget));
+    if (!open_windows_->empty() && open_windows_->front() == widget)
+      open_windows_->erase(open_windows_->begin());
+  }
+
+  delete open_windows_;
+  open_windows_ = nullptr;
+}
 
 void DesktopWindowTreeHostLinux::SetPendingXVisualId(int x_visual_id) {
   pending_x_visual_id_ = x_visual_id;
@@ -106,6 +156,8 @@
 
 void DesktopWindowTreeHostLinux::OnNativeWidgetCreated(
     const Widget::InitParams& params) {
+  window()->SetProperty(kHostForRootWindow, this);
+
   CreateNonClientEventFilter();
   DesktopWindowTreeHostPlatform::OnNativeWidgetCreated(params);
 }
@@ -229,10 +281,26 @@
 }
 
 void DesktopWindowTreeHostLinux::OnClosed() {
+  open_windows().remove(GetAcceleratedWidget());
   DestroyNonClientEventFilter();
   DesktopWindowTreeHostPlatform::OnClosed();
 }
 
+void DesktopWindowTreeHostLinux::OnAcceleratedWidgetAvailable(
+    gfx::AcceleratedWidget widget) {
+  open_windows().push_front(widget);
+  DesktopWindowTreeHostPlatform::OnAcceleratedWidgetAvailable(widget);
+}
+
+void DesktopWindowTreeHostLinux::OnActivationChanged(bool active) {
+  if (active) {
+    auto widget = GetAcceleratedWidget();
+    open_windows().remove(widget);
+    open_windows().insert(open_windows().begin(), widget);
+  }
+  DesktopWindowTreeHostPlatform::OnActivationChanged(active);
+}
+
 void DesktopWindowTreeHostLinux::AddAdditionalInitProperties(
     const Widget::InitParams& params,
     ui::PlatformWindowInitProperties* properties) {
@@ -318,6 +386,12 @@
   return static_cast<ui::PlatformWindowLinux*>(platform_window());
 }
 
+std::list<gfx::AcceleratedWidget>& DesktopWindowTreeHostLinux::open_windows() {
+  if (!open_windows_)
+    open_windows_ = new std::list<gfx::AcceleratedWidget>();
+  return *open_windows_;
+}
+
 // As DWTHX11 subclasses DWTHPlatform through DWTHLinux now (during transition
 // period. see https://crbug.com/990756), we need to guard this factory method.
 // TODO(msisov): remove this guard once DWTHX11 is finally merged into
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
index ceeabac..0dd3955 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
@@ -35,6 +35,23 @@
       DesktopNativeWidgetAura* desktop_native_widget_aura);
   ~DesktopWindowTreeHostLinux() override;
 
+  // A way of converting a |widget| into the content_window()
+  // of the associated DesktopNativeWidgetAura.
+  static aura::Window* GetContentWindowForWidget(gfx::AcceleratedWidget widget);
+
+  // A way of converting a |widget| into this object.
+  static DesktopWindowTreeHostLinux* GetHostForWidget(
+      gfx::AcceleratedWidget widget);
+
+  // Get all open top-level windows. This includes windows that may not be
+  // visible. This list is sorted in their stacking order, i.e. the first window
+  // is the topmost window.
+  static std::vector<aura::Window*> GetAllOpenWindows();
+
+  // Runs the |func| callback for each content-window, and deallocates the
+  // internal list of open windows.
+  static void CleanUpWindowList(void (*func)(aura::Window* window));
+
   // This must be called before the window is created, because the visual cannot
   // be changed after. Useful for X11. Not in use for Wayland.
   void SetPendingXVisualId(int x_visual_id);
@@ -64,6 +81,8 @@
   // PlatformWindowDelegateBase:
   void DispatchEvent(ui::Event* event) override;
   void OnClosed() override;
+  void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) override;
+  void OnActivationChanged(bool active) override;
 
  private:
   FRIEND_TEST_ALL_PREFIXES(DesktopWindowTreeHostLinuxTest, HitTest);
@@ -94,6 +113,9 @@
   const ui::PlatformWindowLinux* GetPlatformWindowLinux() const;
   ui::PlatformWindowLinux* GetPlatformWindowLinux();
 
+  // See comment for variable open_windows_.
+  static std::list<gfx::AcceleratedWidget>& open_windows();
+
   // A handler for events intended for non client area.
   // A posthandler for events intended for non client area. Handles events if no
   // other consumer handled them.
@@ -110,6 +132,10 @@
 
   uint32_t modal_dialog_counter_ = 0;
 
+  // A list of all (top-level) windows that have been created but not yet
+  // destroyed.
+  static std::list<gfx::AcceleratedWidget>* open_windows_;
+
   // The display and the native X window hosting the root window.
   base::WeakPtrFactory<DesktopWindowTreeHostLinux> weak_factory_{this};
 
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index cbcebb0..3f3097b 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -66,18 +66,8 @@
 #include "ui/accessibility/platform/atk_util_auralinux.h"
 #endif
 
-DEFINE_UI_CLASS_PROPERTY_TYPE(views::DesktopWindowTreeHostX11*)
-
 namespace views {
 
-std::list<XID>* DesktopWindowTreeHostX11::open_windows_ = nullptr;
-
-DEFINE_UI_CLASS_PROPERTY_KEY(aura::Window*, kViewsWindowForRootWindow, NULL)
-
-DEFINE_UI_CLASS_PROPERTY_KEY(DesktopWindowTreeHostX11*,
-                             kHostForRootWindow,
-                             NULL)
-
 namespace {
 
 bool ShouldDiscardKeyEvent(XEvent* xev) {
@@ -100,35 +90,12 @@
                                  desktop_native_widget_aura) {}
 
 DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() {
-  window()->ClearProperty(kHostForRootWindow);
   wm::SetWindowMoveClient(window(), nullptr);
 
   // ~DWTHPlatform notifies the DestkopNativeWidgetAura about destruction and
   // also destroyes the dispatcher.
 }
 
-// static
-aura::Window* DesktopWindowTreeHostX11::GetContentWindowForXID(XID xid) {
-  aura::WindowTreeHost* host =
-      aura::WindowTreeHost::GetForAcceleratedWidget(xid);
-  return host ? host->window()->GetProperty(kViewsWindowForRootWindow) : NULL;
-}
-
-// static
-DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::GetHostForXID(XID xid) {
-  aura::WindowTreeHost* host =
-      aura::WindowTreeHost::GetForAcceleratedWidget(xid);
-  return host ? host->window()->GetProperty(kHostForRootWindow) : nullptr;
-}
-
-// static
-std::vector<aura::Window*> DesktopWindowTreeHostX11::GetAllOpenWindows() {
-  std::vector<aura::Window*> windows(open_windows().size());
-  std::transform(open_windows().begin(), open_windows().end(), windows.begin(),
-                 GetContentWindowForXID);
-  return windows;
-}
-
 void DesktopWindowTreeHostX11::AddObserver(
     DesktopWindowTreeHostObserverX11* observer) {
   observer_list_.AddObserver(observer);
@@ -139,21 +106,6 @@
   observer_list_.RemoveObserver(observer);
 }
 
-void DesktopWindowTreeHostX11::CleanUpWindowList(
-    void (*func)(aura::Window* window)) {
-  if (!open_windows_)
-    return;
-  while (!open_windows_->empty()) {
-    gfx::AcceleratedWidget widget = open_windows_->front();
-    func(GetContentWindowForXID(widget));
-    if (!open_windows_->empty() && open_windows_->front() == widget)
-      open_windows_->erase(open_windows_->begin());
-  }
-
-  delete open_windows_;
-  open_windows_ = nullptr;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation:
 
@@ -171,9 +123,6 @@
 
 void DesktopWindowTreeHostX11::OnNativeWidgetCreated(
     const Widget::InitParams& params) {
-  window()->SetProperty(kViewsWindowForRootWindow, GetContentWindow());
-  window()->SetProperty(kHostForRootWindow, this);
-
   // Ensure that the X11DesktopHandler exists so that it tracks create/destroy
   // notify events.
   X11DesktopHandler::get();
@@ -214,41 +163,8 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// DesktopWindowTreeHostX11, private:
-
-std::list<gfx::AcceleratedWidget>& DesktopWindowTreeHostX11::open_windows() {
-  if (!open_windows_)
-    open_windows_ = new std::list<gfx::AcceleratedWidget>();
-  return *open_windows_;
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // DesktopWindowTreeHostX11 implementation:
 
-void DesktopWindowTreeHostX11::OnClosed() {
-  open_windows().remove(GetAcceleratedWidget());
-  DesktopWindowTreeHostLinux::OnClosed();
-}
-
-void DesktopWindowTreeHostX11::OnAcceleratedWidgetAvailable(
-    gfx::AcceleratedWidget widget) {
-  open_windows().push_front(widget);
-  WindowTreeHostPlatform::OnAcceleratedWidgetAvailable(widget);
-}
-
-void DesktopWindowTreeHostX11::OnAcceleratedWidgetDestroyed() {}
-
-void DesktopWindowTreeHostX11::OnActivationChanged(bool active) {
-  if (active) {
-    // TODO(thomasanderson): Remove this window shuffling and use XWindowCache
-    // instead.
-    auto widget = GetAcceleratedWidget();
-    open_windows().remove(widget);
-    open_windows().insert(open_windows().begin(), widget);
-  }
-  DesktopWindowTreeHostPlatform::OnActivationChanged(active);
-}
-
 void DesktopWindowTreeHostX11::OnXWindowMapped() {
   for (DesktopWindowTreeHostObserverX11& observer : observer_list_)
     observer.OnWindowMapped(GetXWindow()->window());
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
index e641d8b..4f4263c7 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -44,25 +44,9 @@
       DesktopNativeWidgetAura* desktop_native_widget_aura);
   ~DesktopWindowTreeHostX11() override;
 
-  // A way of converting an X11 |xid| host window into the content_window()
-  // of the associated DesktopNativeWidgetAura.
-  static aura::Window* GetContentWindowForXID(XID xid);
-
-  // A way of converting an X11 |xid| host window into this object.
-  static DesktopWindowTreeHostX11* GetHostForXID(XID xid);
-
-  // Get all open top-level windows. This includes windows that may not be
-  // visible. This list is sorted in their stacking order, i.e. the first window
-  // is the topmost window.
-  static std::vector<aura::Window*> GetAllOpenWindows();
-
   void AddObserver(DesktopWindowTreeHostObserverX11* observer);
   void RemoveObserver(DesktopWindowTreeHostObserverX11* observer);
 
-  // Runs the |func| callback for each content-window, and deallocates the
-  // internal list of open windows.
-  static void CleanUpWindowList(void (*func)(aura::Window* window));
-
  protected:
   // Overridden from DesktopWindowTreeHost:
   void Init(const Widget::InitParams& params) override;
@@ -78,18 +62,11 @@
  private:
   friend class DesktopWindowTreeHostX11HighDPITest;
 
-  // See comment for variable open_windows_.
-  static std::list<XID>& open_windows();
-
   // PlatformWindowDelegate overrides:
   //
   // DWTHX11 temporarily overrides the PlatformWindowDelegate methods instead of
   // underlying DWTHPlatform and WTHPlatform. Eventually, these will be removed
   // from here as we progress in https://crbug.com/990756.
-  void OnClosed() override;
-  void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) override;
-  void OnAcceleratedWidgetDestroyed() override;
-  void OnActivationChanged(bool active) override;
   void OnXWindowMapped() override;
   void OnXWindowUnmapped() override;
 
@@ -111,10 +88,6 @@
   base::ObserverList<DesktopWindowTreeHostObserverX11>::Unchecked
       observer_list_;
 
-  // A list of all (top-level) windows that have been created but not yet
-  // destroyed.
-  static std::list<gfx::AcceleratedWidget>* open_windows_;
-
   // The display and the native X window hosting the root window.
   base::WeakPtrFactory<DesktopWindowTreeHostX11> weak_factory_{this};
 
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
index f82417b..1c43e58 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
@@ -454,7 +454,7 @@
   ASSERT_NE(parent_widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget(),
             child_widget.GetNativeWindow()->GetHost()->GetAcceleratedWidget());
   Widget::CloseAllSecondaryWidgets();
-  EXPECT_TRUE(DesktopWindowTreeHostX11::GetAllOpenWindows().empty());
+  EXPECT_TRUE(DesktopWindowTreeHostLinux::GetAllOpenWindows().empty());
 }
 
 // A Widget that allows setting the min/max size for the widget.
diff --git a/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc b/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc
index 4ef8e358e..670b2e1 100644
--- a/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc
+++ b/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc
@@ -23,7 +23,7 @@
   ignore_ = ignore;
 
   std::vector<aura::Window*> local_process_windows =
-      DesktopWindowTreeHostX11::GetAllOpenWindows();
+      DesktopWindowTreeHostLinux::GetAllOpenWindows();
   if (std::none_of(local_process_windows.cbegin(), local_process_windows.cend(),
                    [this](auto* window) {
                      return ShouldStopIteratingAtLocalProcessWindow(window);
@@ -31,7 +31,8 @@
     return nullptr;
 
   ui::EnumerateTopLevelWindows(this);
-  return DesktopWindowTreeHostX11::GetContentWindowForXID(toplevel_);
+  return DesktopWindowTreeHostLinux::GetContentWindowForWidget(
+      static_cast<gfx::AcceleratedWidget>(toplevel_));
 }
 
 XID X11TopmostWindowFinder::FindWindowAt(
@@ -45,8 +46,8 @@
   if (!ui::IsWindowVisible(xid))
     return false;
 
-  aura::Window* window =
-      views::DesktopWindowTreeHostX11::GetContentWindowForXID(xid);
+  auto* window = DesktopWindowTreeHostLinux::GetContentWindowForWidget(
+      static_cast<gfx::AcceleratedWidget>(xid));
   if (window) {
     if (ShouldStopIteratingAtLocalProcessWindow(window)) {
       toplevel_ = xid;
@@ -72,9 +73,11 @@
   if (!window->IsVisible())
     return false;
 
-  DesktopWindowTreeHostX11* host = DesktopWindowTreeHostX11::GetHostForXID(
+  auto* host = DesktopWindowTreeHostLinux::GetHostForWidget(
       window->GetHost()->GetAcceleratedWidget());
-  if (!host->GetXRootWindowOuterBounds().Contains(screen_loc_in_pixels_))
+  if (!static_cast<DesktopWindowTreeHostX11*>(host)
+           ->GetXRootWindowOuterBounds()
+           .Contains(screen_loc_in_pixels_))
     return false;
 
   aura::client::ScreenPositionClient* screen_position_client =
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index 894b80a..0769f9b6 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -59,7 +59,7 @@
 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
 #endif
 
-#if defined(USE_X11)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
 #include "ui/views/linux_ui/linux_ui.h"
 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
 #endif
@@ -1065,7 +1065,7 @@
 // Widget, public:
 
 namespace {
-#if defined(OS_WIN) || defined(USE_X11)
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
 void CloseWindow(aura::Window* window) {
   if (window) {
     Widget* widget = Widget::GetWidgetForNativeView(window);
@@ -1095,13 +1095,13 @@
   EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, 0);
 #endif
 
-#if defined(USE_X11)
-  DesktopWindowTreeHostX11::CleanUpWindowList(CloseWindow);
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+  DesktopWindowTreeHostLinux::CleanUpWindowList(CloseWindow);
 #endif
 }
 
 const ui::NativeTheme* Widget::GetNativeTheme() const {
-#if defined(USE_X11)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
   const LinuxUI* linux_ui = LinuxUI::instance();
   if (linux_ui) {
     ui::NativeTheme* native_theme =
diff --git a/ui/views/window/dialog_delegate_unittest.cc b/ui/views/window/dialog_delegate_unittest.cc
index 7dc2afb..57b32e6 100644
--- a/ui/views/window/dialog_delegate_unittest.cc
+++ b/ui/views/window/dialog_delegate_unittest.cc
@@ -309,7 +309,7 @@
   frame->ResetWindowControls();
 
   const gfx::Rect close_button_bounds =
-      frame->GetCloseButtonForTest()->bounds();
+      frame->GetCloseButtonForTesting()->bounds();
   EXPECT_EQ(HTCLOSE,
             frame->NonClientHitTest(gfx::Point(close_button_bounds.x() + 4,
                                                close_button_bounds.y() + 4)));