diff --git a/.gitignore b/.gitignore
index fa545ff..93b62c81 100644
--- a/.gitignore
+++ b/.gitignore
@@ -302,3 +302,6 @@
 
 # Ignore IntelliJ files.
 .idea/
+
+# Ignore the default results output directory for tools/run-swarmed.py
+/results
diff --git a/DEPS b/DEPS
index b5ce894c..10864f6 100644
--- a/DEPS
+++ b/DEPS
@@ -162,7 +162,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '4fe30e15c06c991c3c0c651ef9974fc402e611e0',
+  'skia_revision': 'c091a1b5c085ad3fccc1507caaf2be7ff124d62a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -197,7 +197,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling googletest
   # and whatever else without interference from each other.
-  'googletest_revision': '3a45039862471cc2785e92bd19bd146c70344986',
+  'googletest_revision': '33a0d4f6d76a0ed6061e612848532cba82d42870',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling lighttpd
   # and whatever else without interference from each other.
@@ -217,7 +217,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # and whatever else without interference from each other.
-  'harfbuzz_revision': 'bbad1b8298125d78c159ed7fdd7bde6a3f3fff56',
+  'harfbuzz_revision': '170b5dd856b1ba8f26e79863fe0c64a52eb68951',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Emoji Segmenter
   # and whatever else without interference from each other.
@@ -225,7 +225,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': '369f46e37423495f0d40f9088b60d6a3fb0e39bb',
+  'catapult_revision': '050abd8dd5c49167d4d33864f3c078d270d271af',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -297,7 +297,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': '619935f7f249a41c6c839653fe1ad2045fc1c5b4',
+  'dawn_revision': 'f35dcfe60a62cfb76ee557edd4d5bad0068f2850',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -857,7 +857,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'db31812cb2392fe5565076b26fa46084c4bcbd88',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '2f0f741fd31bc05c7d157939eba994be4d3a526d',
       'condition': 'checkout_linux',
   },
 
@@ -867,7 +867,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'dbca865e55f706efc3843eab2e88a65aa810be49',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'cc6f585f055ae696170b22f0e8db906d27afe636',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1246,7 +1246,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'c85e95e7f84b90619edc118575ee15abd6dc3514',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'b2f1e4bfc51fc79f0fd7a7aaef5cc68566bc31c8',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1414,7 +1414,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'abaae129d9a0c6e1e092067e0b105475df43352e',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'c5d29588605e73b51d8da88095fb1a955ccc648f',
+    Var('webrtc_git') + '/src.git' + '@' + '55f663f5ddff7be2943a528fc6896c220de45599',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1455,7 +1455,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2f637a9deab96aeba4104831dd92c7664b4a4b24',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ea8664557d2e1199be7251933953f46f5a8cd39d',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 997e106..917e366d8 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -399,6 +399,11 @@
   host->AddFilter(new cdm::CdmMessageFilterAndroid(true, false));
 }
 
+bool AwContentBrowserClient::IsExplicitNavigation(
+    ui::PageTransition transition) {
+  return ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED);
+}
+
 bool AwContentBrowserClient::ShouldUseMobileFlingCurve() {
   return true;
 }
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index f45134f..f67f2d1e 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -64,6 +64,7 @@
   content::WebContentsViewDelegate* GetWebContentsViewDelegate(
       content::WebContents* web_contents) override;
   void RenderProcessWillLaunch(content::RenderProcessHost* host) override;
+  bool IsExplicitNavigation(ui::PageTransition transition) override;
   bool ShouldUseMobileFlingCurve() override;
   bool IsHandledURL(const GURL& url) override;
   bool ForceSniffingFileUrlsForHtml() override;
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index f73f203..fbe1ff3 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1106,6 +1106,8 @@
     "wm/desks/desk_preview_view.h",
     "wm/desks/desks_animations.cc",
     "wm/desks/desks_animations.h",
+    "wm/desks/desks_bar_item_border.cc",
+    "wm/desks/desks_bar_item_border.h",
     "wm/desks/desks_bar_view.cc",
     "wm/desks/desks_bar_view.h",
     "wm/desks/desks_controller.cc",
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index fae519f..1dce1720 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -645,7 +645,7 @@
 }
 
 void AppListControllerImpl::OnAssistantStatusChanged(
-    mojom::VoiceInteractionState state) {
+    mojom::AssistantState state) {
   UpdateAssistantVisibility();
 }
 
@@ -1177,8 +1177,7 @@
   auto* state = AssistantState::Get();
   return state->settings_enabled().value_or(false) &&
          state->allowed_state() == mojom::AssistantAllowedState::ALLOWED &&
-         state->voice_interaction_state() !=
-             mojom::VoiceInteractionState::NOT_READY;
+         state->assistant_state() != mojom::AssistantState::NOT_READY;
 }
 
 bool AppListControllerImpl::ShouldShowAssistantPrivacyInfo() const {
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h
index 7bcd3d3..6842fbcc 100644
--- a/ash/app_list/app_list_controller_impl.h
+++ b/ash/app_list/app_list_controller_impl.h
@@ -27,7 +27,6 @@
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/tablet_mode_observer.h"
 #include "ash/public/cpp/wallpaper_controller_observer.h"
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
 #include "ash/session/session_observer.h"
 #include "ash/shell_observer.h"
 #include "ash/wm/mru_window_tracker.h"
@@ -239,7 +238,7 @@
   void OnWallpaperColorsChanged() override;
 
   // AssistantStateObserver:
-  void OnAssistantStatusChanged(mojom::VoiceInteractionState state) override;
+  void OnAssistantStatusChanged(mojom::AssistantState state) override;
   void OnAssistantSettingsEnabled(bool enabled) override;
   void OnAssistantFeatureAllowedChanged(
       mojom::AssistantAllowedState state) override;
diff --git a/ash/assistant/assistant_controller.cc b/ash/assistant/assistant_controller.cc
index ba4d4b68..8f9123c 100644
--- a/ash/assistant/assistant_controller.cc
+++ b/ash/assistant/assistant_controller.cc
@@ -324,8 +324,8 @@
 }
 
 void AssistantController::OnAssistantStatusChanged(
-    mojom::VoiceInteractionState state) {
-  if (state == mojom::VoiceInteractionState::NOT_READY)
+    mojom::AssistantState state) {
+  if (state == mojom::AssistantState::NOT_READY)
     assistant_ui_controller_.CloseUi(AssistantExitPoint::kUnspecified);
 }
 
diff --git a/ash/assistant/assistant_controller.h b/ash/assistant/assistant_controller.h
index 5a266e3..853113b8 100644
--- a/ash/assistant/assistant_controller.h
+++ b/ash/assistant/assistant_controller.h
@@ -156,7 +156,7 @@
   void NotifyUrlOpened(const GURL& url, bool from_server);
 
   // AssistantStateObserver:
-  void OnAssistantStatusChanged(mojom::VoiceInteractionState state) override;
+  void OnAssistantStatusChanged(mojom::AssistantState state) override;
   void OnLockedFullScreenStateChanged(bool enabled) override;
 
   // AssistantInterfaceBinder implementation:
diff --git a/ash/assistant/assistant_setup_controller.cc b/ash/assistant/assistant_setup_controller.cc
index 78500937..52a5f91 100644
--- a/ash/assistant/assistant_setup_controller.cc
+++ b/ash/assistant/assistant_setup_controller.cc
@@ -8,7 +8,6 @@
 #include "ash/assistant/assistant_ui_controller.h"
 #include "ash/assistant/util/deep_link_util.h"
 #include "ash/assistant/util/i18n_util.h"
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
 #include "ash/shell.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
diff --git a/ash/assistant/assistant_suggestions_controller.h b/ash/assistant/assistant_suggestions_controller.h
index 68a2bd37..80fee8a 100644
--- a/ash/assistant/assistant_suggestions_controller.h
+++ b/ash/assistant/assistant_suggestions_controller.h
@@ -12,7 +12,6 @@
 #include "ash/assistant/model/assistant_ui_model_observer.h"
 #include "ash/public/cpp/assistant/assistant_state.h"
 #include "ash/public/cpp/assistant/proactive_suggestions_client.h"
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
 #include "base/macros.h"
 
 namespace ash {
diff --git a/ash/assistant/assistant_ui_controller.cc b/ash/assistant/assistant_ui_controller.cc
index 9c2be42..fd39c19 100644
--- a/ash/assistant/assistant_ui_controller.cc
+++ b/ash/assistant/assistant_ui_controller.cc
@@ -400,8 +400,8 @@
     base::Optional<AssistantExitPoint> exit_point) {
   AssistantState::Get()->NotifyStatusChanged(
       new_visibility == AssistantVisibility::kVisible
-          ? mojom::VoiceInteractionState::RUNNING
-          : mojom::VoiceInteractionState::STOPPED);
+          ? mojom::AssistantState::VISIBLE
+          : mojom::AssistantState::READY);
 
   switch (new_visibility) {
     case AssistantVisibility::kClosed:
@@ -487,8 +487,7 @@
   }
 
   // TODO(dmblack): Show a more helpful message to the user.
-  if (assistant_state->voice_interaction_state() ==
-      mojom::VoiceInteractionState::NOT_READY) {
+  if (assistant_state->assistant_state() == mojom::AssistantState::NOT_READY) {
     ShowToast(kUnboundServiceToastId, IDS_ASH_ASSISTANT_ERROR_GENERIC);
     return;
   }
diff --git a/ash/assistant/test/assistant_ash_test_base.cc b/ash/assistant/test/assistant_ash_test_base.cc
index 1a02cebf..0b14d9c1 100644
--- a/ash/assistant/test/assistant_ash_test_base.cc
+++ b/ash/assistant/test/assistant_ash_test_base.cc
@@ -38,8 +38,7 @@
 
   // At this point our Assistant service is ready for use.
   // Indicate this by changing status from NOT_READY to STOPPED.
-  AssistantState::Get()->NotifyStatusChanged(
-      mojom::VoiceInteractionState::STOPPED);
+  AssistantState::Get()->NotifyStatusChanged(mojom::AssistantState::READY);
 
   DisableAnimations();
 }
diff --git a/ash/assistant/ui/assistant_container_view_unittest.cc b/ash/assistant/ui/assistant_container_view_unittest.cc
index cc2cdb6..85c1af5e 100644
--- a/ash/assistant/ui/assistant_container_view_unittest.cc
+++ b/ash/assistant/ui/assistant_container_view_unittest.cc
@@ -46,8 +46,7 @@
 
     // After mocks are set up our Assistant service is ready for use. Indicate
     // this by changing status from NOT_READY to STOPPED.
-    AssistantState::Get()->NotifyStatusChanged(
-        mojom::VoiceInteractionState::STOPPED);
+    AssistantState::Get()->NotifyStatusChanged(mojom::AssistantState::READY);
   }
 
   AssistantUiController* ui_controller() { return ui_controller_; }
diff --git a/ash/media/media_notification_container_impl.h b/ash/media/media_notification_container_impl.h
index e679d14..aa3dd5d 100644
--- a/ash/media/media_notification_container_impl.h
+++ b/ash/media/media_notification_container_impl.h
@@ -39,6 +39,9 @@
 
   // media_message_center::MediaNotificationContainer:
   void OnExpanded(bool expanded) override;
+  void OnMediaSessionInfoChanged(
+      const media_session::mojom::MediaSessionInfoPtr& session_info) override {}
+  void OnForegoundColorChanged(SkColor color) override {}
 
   // views::View:
   void OnMouseEvent(ui::MouseEvent* event) override;
diff --git a/ash/public/cpp/assistant/assistant_state.cc b/ash/public/cpp/assistant/assistant_state.cc
index 1f4a3ee..c8e276d 100644
--- a/ash/public/cpp/assistant/assistant_state.cc
+++ b/ash/public/cpp/assistant/assistant_state.cc
@@ -34,8 +34,8 @@
   bindings_.AddBinding(this, std::move(request));
 }
 
-void AssistantState::NotifyStatusChanged(mojom::VoiceInteractionState state) {
-  if (voice_interaction_state_ == state)
+void AssistantState::NotifyStatusChanged(mojom::AssistantState state) {
+  if (assistant_state_ == state)
     return;
 
   UpdateAssistantStatus(state);
diff --git a/ash/public/cpp/assistant/assistant_state.h b/ash/public/cpp/assistant/assistant_state.h
index dd7ae6b..60d76e6 100644
--- a/ash/public/cpp/assistant/assistant_state.h
+++ b/ash/public/cpp/assistant/assistant_state.h
@@ -9,7 +9,6 @@
 
 #include "ash/public/cpp/assistant/assistant_state_base.h"
 #include "ash/public/mojom/assistant_state_controller.mojom.h"
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/interface_ptr_set.h"
@@ -27,7 +26,7 @@
   ~AssistantState() override;
 
   void BindRequest(mojom::AssistantStateControllerRequest request);
-  void NotifyStatusChanged(mojom::VoiceInteractionState state);
+  void NotifyStatusChanged(mojom::AssistantState state);
   void NotifyFeatureAllowed(mojom::AssistantAllowedState state);
   void NotifyLocaleChanged(const std::string& locale);
   void NotifyArcPlayStoreEnabledChanged(bool enabled);
diff --git a/ash/public/cpp/assistant/assistant_state_base.cc b/ash/public/cpp/assistant/assistant_state_base.cc
index 4d7062e..c209503 100644
--- a/ash/public/cpp/assistant/assistant_state_base.cc
+++ b/ash/public/cpp/assistant/assistant_state_base.cc
@@ -35,7 +35,7 @@
 std::string AssistantStateBase::ToString() const {
   std::stringstream result;
   result << "AssistantState:";
-  result << voice_interaction_state_;
+  result << assistant_state_;
   PRINT_VALUE(settings_enabled);
   PRINT_VALUE(context_enabled);
   PRINT_VALUE(hotword_enabled);
@@ -123,7 +123,7 @@
 
 void AssistantStateBase::InitializeObserverMojom(
     mojom::AssistantStateObserver* observer) {
-  observer->OnAssistantStatusChanged(voice_interaction_state_);
+  observer->OnAssistantStatusChanged(assistant_state_);
   if (allowed_state_.has_value())
     observer->OnAssistantFeatureAllowedChanged(allowed_state_.value());
   if (locale_.has_value())
@@ -216,11 +216,10 @@
     observer.OnAssistantNotificationEnabled(notification_enabled_.value());
 }
 
-void AssistantStateBase::UpdateAssistantStatus(
-    mojom::VoiceInteractionState state) {
-  voice_interaction_state_ = state;
+void AssistantStateBase::UpdateAssistantStatus(mojom::AssistantState state) {
+  assistant_state_ = state;
   for (auto& observer : observers_)
-    observer.OnAssistantStatusChanged(voice_interaction_state_);
+    observer.OnAssistantStatusChanged(assistant_state_);
 }
 
 void AssistantStateBase::UpdateFeatureAllowedState(
diff --git a/ash/public/cpp/assistant/assistant_state_base.h b/ash/public/cpp/assistant/assistant_state_base.h
index c9861c8d..b956e49 100644
--- a/ash/public/cpp/assistant/assistant_state_base.h
+++ b/ash/public/cpp/assistant/assistant_state_base.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "ash/public/mojom/assistant_state_controller.mojom.h"
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
 #include "base/macros.h"
 #include "base/optional.h"
 #include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
@@ -35,8 +34,7 @@
   virtual void OnAssistantNotificationEnabled(bool notification_enabled) {}
 
   // mojom::AssistantStateObserver:
-  void OnAssistantStatusChanged(
-      ash::mojom::VoiceInteractionState state) override {}
+  void OnAssistantStatusChanged(ash::mojom::AssistantState state) override {}
   void OnAssistantFeatureAllowedChanged(
       ash::mojom::AssistantAllowedState state) override {}
   void OnArcPlayStoreEnabledChanged(bool enabled) override {}
@@ -57,9 +55,7 @@
   AssistantStateBase();
   virtual ~AssistantStateBase();
 
-  const mojom::VoiceInteractionState& voice_interaction_state() const {
-    return voice_interaction_state_;
-  }
+  mojom::AssistantState assistant_state() const { return assistant_state_; }
 
   const base::Optional<bool>& settings_enabled() const {
     return settings_enabled_;
@@ -122,14 +118,13 @@
   void UpdateNotificationEnabled();
 
   // Called when new values of the listened states are received.
-  void UpdateAssistantStatus(mojom::VoiceInteractionState state);
+  void UpdateAssistantStatus(mojom::AssistantState state);
   void UpdateFeatureAllowedState(mojom::AssistantAllowedState state);
   void UpdateLocale(const std::string& locale);
   void UpdateArcPlayStoreEnabled(bool enabled);
   void UpdateLockedFullScreenState(bool enabled);
 
-  mojom::VoiceInteractionState voice_interaction_state_ =
-      mojom::VoiceInteractionState::NOT_READY;
+  mojom::AssistantState assistant_state_ = mojom::AssistantState::NOT_READY;
 
   // TODO(b/138679823): Maybe remove Optional for preference values.
   // Whether the Assistant is enabled in system settings. nullopt if the
diff --git a/ash/public/mojom/assistant_state_controller.mojom b/ash/public/mojom/assistant_state_controller.mojom
index 42b924f..3edb73e 100644
--- a/ash/public/mojom/assistant_state_controller.mojom
+++ b/ash/public/mojom/assistant_state_controller.mojom
@@ -4,12 +4,44 @@
 
 module ash.mojom;
 
-import "ash/public/mojom/voice_interaction_controller.mojom";
+// The initial state is NOT_READY, after Assistant service started it becomes
+// READY. When Assistant UI shows up the state becomes VISIBLE.
+enum AssistantState {
+  // The Assistant service is not ready yet.
+  NOT_READY = 0,
+  // The Assistant service is ready.
+  READY,
+  // The Assistant UI is showing.
+  VISIBLE
+};
+
+enum AssistantAllowedState {
+  // Assistant feature is allowed.
+  ALLOWED = 0,
+  // Disallowed because search and assistant is disabled by policy.
+  DISALLOWED_BY_POLICY,
+  // Disallowed because user's locale is not compatible.
+  DISALLOWED_BY_LOCALE,
+  // Disallowed because current user is not primary user.
+  DISALLOWED_BY_NONPRIMARY_USER,
+  // Disallowed because current user is supervised user.
+  DISALLOWED_BY_SUPERVISED_USER,
+  // Disallowed because incognito mode.
+  DISALLOWED_BY_INCOGNITO,
+  // Disallowed because the device is in demo mode.
+  DISALLOWED_BY_DEMO_MODE,
+  // Disallowed because the device is in public session.
+  DISALLOWED_BY_PUBLIC_SESSION,
+  // Disallowed because the user's account type is currently not supported.
+  DISALLOWED_BY_ACCOUNT_TYPE,
+  // Disallowed because the device is in Kiosk mode.
+  DISALLOWED_BY_KIOSK_MODE
+};
 
 // Allows observing changes to Assistant status and settings.
 interface AssistantStateObserver {
   // Called when Assistant state changes.
-  OnAssistantStatusChanged(VoiceInteractionState state);
+  OnAssistantStatusChanged(AssistantState state);
 
   // Called when assistant feature allowed state has changed.
   OnAssistantFeatureAllowedChanged(AssistantAllowedState state);
diff --git a/ash/public/mojom/voice_interaction_controller.mojom b/ash/public/mojom/voice_interaction_controller.mojom
index 8f19c8eb..64b3fc49 100644
--- a/ash/public/mojom/voice_interaction_controller.mojom
+++ b/ash/public/mojom/voice_interaction_controller.mojom
@@ -21,63 +21,3 @@
   // Voice interaction session is currently running.
   RUNNING
 };
-
-enum AssistantAllowedState {
-  // Assistant feature is allowed.
-  ALLOWED = 0,
-  // Disallowed because search and assistant is disabled by policy.
-  DISALLOWED_BY_POLICY,
-  // Disallowed because user's locale is not compatible.
-  DISALLOWED_BY_LOCALE,
-  // Disallowed because current user is not primary user.
-  DISALLOWED_BY_NONPRIMARY_USER,
-  // Disallowed because current user is supervised user.
-  DISALLOWED_BY_SUPERVISED_USER,
-  // Disallowed because incognito mode.
-  DISALLOWED_BY_INCOGNITO,
-  // Disallowed because the device is in demo mode.
-  DISALLOWED_BY_DEMO_MODE,
-  // Disallowed because the device is in public session.
-  DISALLOWED_BY_PUBLIC_SESSION,
-  // Disallowed because the user's account type is currently not supported.
-  DISALLOWED_BY_ACCOUNT_TYPE,
-  // Disallowed because the device is in Kiosk mode.
-  DISALLOWED_BY_KIOSK_MODE
-};
-
-// Allows observing changes to voice interaction status and settings.
-interface VoiceInteractionObserver {
-  // Called when voice interaction session state changes.
-  OnVoiceInteractionStatusChanged(VoiceInteractionState state);
-
-  // Called when voice interaction is enabled/disabled in settings.
-  OnVoiceInteractionSettingsEnabled(bool enabled);
-
-  // Called when voice interaction service is allowed/disallowed to access
-  // the "context" (text and graphic content that is currently on screen).
-  OnVoiceInteractionContextEnabled(bool enabled);
-
-  // Called when hotword listening is enabled/disabled.
-  OnVoiceInteractionHotwordEnabled(bool enabled);
-
-  // Called when assistant feature allowed state has changed.
-  OnAssistantFeatureAllowedChanged(AssistantAllowedState state);
-
-  // Called when Google Play Store is enabled/disabled.
-  OnArcPlayStoreEnabledChanged(bool enabled);
-
-  // Called when locale is changed in pref. The locale is in the format can be
-  // "en-US" or simply "en". When locale is not set in pref, it returns empty
-  // string.
-  OnLocaleChanged(string locale);
-
-  // Called when locked full screen state has changed.
-  OnLockedFullScreenStateChanged(bool enabled);
-};
-
-// Interface for ash client (Chrome) to connect to the voice interaction
-// controller, which notifies changes of voice interaction related flags.
-interface VoiceInteractionController {
-  // Add an observer.
-  AddObserver(VoiceInteractionObserver observer);
-};
diff --git a/ash/shelf/home_button_controller.cc b/ash/shelf/home_button_controller.cc
index a481952..5f45bd6 100644
--- a/ash/shelf/home_button_controller.cc
+++ b/ash/shelf/home_button_controller.cc
@@ -141,8 +141,10 @@
 }
 
 bool HomeButtonController::IsVoiceInteractionRunning() {
-  return AssistantState::Get()->voice_interaction_state() ==
-         mojom::VoiceInteractionState::RUNNING;
+  // TODO(b/140823590): Update the method name/description and use Assistant
+  // visibility state instead.
+  return AssistantState::Get()->assistant_state() ==
+         mojom::AssistantState::VISIBLE;
 }
 
 void HomeButtonController::OnAppListVisibilityChanged(bool shown,
@@ -171,21 +173,21 @@
 }
 
 void HomeButtonController::OnAssistantStatusChanged(
-    mojom::VoiceInteractionState state) {
+    mojom::AssistantState state) {
   button_->OnVoiceInteractionAvailabilityChanged();
 
   if (!assistant_overlay_)
     return;
 
   switch (state) {
-    case mojom::VoiceInteractionState::STOPPED:
+    case mojom::AssistantState::READY:
       UMA_HISTOGRAM_TIMES(
           "VoiceInteraction.OpenDuration",
           base::TimeTicks::Now() - voice_interaction_start_timestamp_);
       break;
-    case mojom::VoiceInteractionState::NOT_READY:
+    case mojom::AssistantState::NOT_READY:
       break;
-    case mojom::VoiceInteractionState::RUNNING:
+    case mojom::AssistantState::VISIBLE:
       // we start hiding the animation if it is running.
       if (assistant_overlay_->IsBursting() || assistant_overlay_->IsWaiting()) {
         assistant_animation_hide_delay_timer_->Start(
diff --git a/ash/shelf/home_button_controller.h b/ash/shelf/home_button_controller.h
index 30a9a4c..d54cb1d4 100644
--- a/ash/shelf/home_button_controller.h
+++ b/ash/shelf/home_button_controller.h
@@ -10,7 +10,6 @@
 #include "ash/app_list/app_list_controller_observer.h"
 #include "ash/public/cpp/assistant/assistant_state.h"
 #include "ash/public/cpp/tablet_mode_observer.h"
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
 #include "ash/session/session_observer.h"
 #include "base/macros.h"
 
@@ -62,7 +61,7 @@
   void OnTabletModeStarted() override;
 
   // AssistantStateObserver:
-  void OnAssistantStatusChanged(mojom::VoiceInteractionState state) override;
+  void OnAssistantStatusChanged(mojom::AssistantState state) override;
   void OnAssistantSettingsEnabled(bool enabled) override;
 
   void OnAppListShown();
diff --git a/ash/shelf/home_button_unittest.cc b/ash/shelf/home_button_unittest.cc
index 5613267b..d965b9a 100644
--- a/ash/shelf/home_button_unittest.cc
+++ b/ash/shelf/home_button_unittest.cc
@@ -181,7 +181,7 @@
   prefs()->SetBoolean(chromeos::assistant::prefs::kAssistantEnabled, true);
   assistant_state()->NotifyFeatureAllowed(
       mojom::AssistantAllowedState::ALLOWED);
-  assistant_state()->NotifyStatusChanged(mojom::VoiceInteractionState::STOPPED);
+  assistant_state()->NotifyStatusChanged(mojom::AssistantState::READY);
 
   ui::GestureEvent long_press =
       CreateGestureEvent(ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
diff --git a/ash/system/palette/palette_tray_unittest.cc b/ash/system/palette/palette_tray_unittest.cc
index 85cbc0f..d8313cdd 100644
--- a/ash/system/palette/palette_tray_unittest.cc
+++ b/ash/system/palette/palette_tray_unittest.cc
@@ -16,7 +16,6 @@
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/assistant/assistant_state.h"
 #include "ash/public/cpp/stylus_utils.h"
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/session/test_session_controller_client.h"
@@ -338,7 +337,7 @@
 TEST_F(PaletteTrayTestWithAssistant, MetalayerToolActivatesHighlighter) {
   ui::ScopedAnimationDurationScaleMode animation_duration_mode(
       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
-  assistant_state()->NotifyStatusChanged(mojom::VoiceInteractionState::RUNNING);
+  assistant_state()->NotifyStatusChanged(mojom::AssistantState::VISIBLE);
   prefs()->SetBoolean(chromeos::assistant::prefs::kAssistantEnabled, true);
   prefs()->SetBoolean(chromeos::assistant::prefs::kAssistantContextEnabled,
                       true);
@@ -417,8 +416,7 @@
 TEST_F(PaletteTrayTestWithAssistant, StylusBarrelButtonActivatesHighlighter) {
   ui::ScopedAnimationDurationScaleMode animation_duration_mode(
       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
-  assistant_state()->NotifyStatusChanged(
-      mojom::VoiceInteractionState::NOT_READY);
+  assistant_state()->NotifyStatusChanged(mojom::AssistantState::NOT_READY);
   prefs()->SetBoolean(chromeos::assistant::prefs::kAssistantEnabled, false);
   prefs()->SetBoolean(chromeos::assistant::prefs::kAssistantContextEnabled,
                       false);
@@ -454,7 +452,7 @@
                              false /* no highlighter on press */);
 
   // Once the service is ready, the button should start working.
-  assistant_state()->NotifyStatusChanged(mojom::VoiceInteractionState::RUNNING);
+  assistant_state()->NotifyStatusChanged(mojom::AssistantState::VISIBLE);
 
   // Press and drag with no button, still no highlighter.
   WaitDragAndAssertMetalayer("all enabled, no button ", origin, ui::EF_NONE,
diff --git a/ash/system/palette/tools/metalayer_mode.cc b/ash/system/palette/tools/metalayer_mode.cc
index 4360b41e..b02fdaa 100644
--- a/ash/system/palette/tools/metalayer_mode.cc
+++ b/ash/system/palette/tools/metalayer_mode.cc
@@ -150,9 +150,8 @@
   event->StopPropagation();
 }
 
-void MetalayerMode::OnAssistantStatusChanged(
-    mojom::VoiceInteractionState state) {
-  voice_interaction_state_ = state;
+void MetalayerMode::OnAssistantStatusChanged(mojom::AssistantState state) {
+  assistant_state_ = state;
   UpdateState();
 }
 
diff --git a/ash/system/palette/tools/metalayer_mode.h b/ash/system/palette/tools/metalayer_mode.h
index 4df15b6..678bf9f 100644
--- a/ash/system/palette/tools/metalayer_mode.h
+++ b/ash/system/palette/tools/metalayer_mode.h
@@ -8,7 +8,6 @@
 #include "ash/ash_export.h"
 #include "ash/highlighter/highlighter_controller.h"
 #include "ash/public/cpp/assistant/assistant_state.h"
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
 #include "ash/system/palette/common_palette_tool.h"
 #include "base/memory/weak_ptr.h"
 #include "ui/events/event_handler.h"
@@ -40,14 +39,14 @@
   // Whether the tool is in "loading" state.
   bool loading() const {
     return feature_enabled() &&
-           voice_interaction_state_ == mojom::VoiceInteractionState::NOT_READY;
+           assistant_state_ == mojom::AssistantState::NOT_READY;
   }
 
   // Whether the tool can be selected from the menu (only true when enabled
   // by the user and fully loaded).
   bool selectable() const {
     return feature_enabled() &&
-           voice_interaction_state_ != mojom::VoiceInteractionState::NOT_READY;
+           assistant_state_ != mojom::AssistantState::NOT_READY;
   }
 
   // PaletteTool:
@@ -65,7 +64,7 @@
   void OnTouchEvent(ui::TouchEvent* event) override;
 
   // AssistantStateObserver:
-  void OnAssistantStatusChanged(mojom::VoiceInteractionState state) override;
+  void OnAssistantStatusChanged(mojom::AssistantState state) override;
   void OnAssistantSettingsEnabled(bool enabled) override;
   void OnAssistantContextEnabled(bool enabled) override;
   void OnAssistantFeatureAllowedChanged(
@@ -83,8 +82,7 @@
   // Called when the metalayer session is complete.
   void OnMetalayerSessionComplete();
 
-  mojom::VoiceInteractionState voice_interaction_state_ =
-      mojom::VoiceInteractionState::NOT_READY;
+  mojom::AssistantState assistant_state_ = mojom::AssistantState::NOT_READY;
 
   bool assistant_enabled_ = false;
 
diff --git a/ash/system/palette/tools/metalayer_unittest.cc b/ash/system/palette/tools/metalayer_unittest.cc
index e382c90..dcde9f70 100644
--- a/ash/system/palette/tools/metalayer_unittest.cc
+++ b/ash/system/palette/tools/metalayer_unittest.cc
@@ -7,7 +7,6 @@
 #include "ash/highlighter/highlighter_controller.h"
 #include "ash/highlighter/highlighter_controller_test_api.h"
 #include "ash/public/cpp/assistant/assistant_state.h"
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
 #include "ash/system/palette/mock_palette_tool_delegate.h"
@@ -71,10 +70,9 @@
 // The metalayer tool is always visible, but only enabled when the user
 // has enabled the metalayer AND the voice interaction framework is ready.
 TEST_F(MetalayerToolTest, PaletteMenuState) {
-  const mojom::VoiceInteractionState kStates[] = {
-      mojom::VoiceInteractionState::NOT_READY,
-      mojom::VoiceInteractionState::STOPPED,
-      mojom::VoiceInteractionState::RUNNING};
+  const mojom::AssistantState kStates[] = {mojom::AssistantState::NOT_READY,
+                                           mojom::AssistantState::READY,
+                                           mojom::AssistantState::VISIBLE};
   const mojom::AssistantAllowedState kAllowedStates[] = {
       mojom::AssistantAllowedState::ALLOWED,
       mojom::AssistantAllowedState::DISALLOWED_BY_POLICY,
@@ -86,13 +84,13 @@
   const base::string16 kLoading(base::ASCIIToUTF16("loading"));
 
   // Iterate over every possible combination of states.
-  for (mojom::VoiceInteractionState state : kStates) {
+  for (mojom::AssistantState state : kStates) {
     for (mojom::AssistantAllowedState allowed_state : kAllowedStates) {
       for (int enabled = 0; enabled <= 1; enabled++) {
         for (int context = 0; context <= 1; context++) {
           const bool allowed =
               allowed_state == mojom::AssistantAllowedState::ALLOWED;
-          const bool ready = state != mojom::VoiceInteractionState::NOT_READY;
+          const bool ready = state != mojom::AssistantState::NOT_READY;
           const bool selectable = allowed && enabled && context && ready;
 
           assistant_state()->NotifyStatusChanged(state);
@@ -146,7 +144,7 @@
 
 // Verifies that disabling the metalayer support disables the tool.
 TEST_F(MetalayerToolTest, MetalayerUnsupportedDisablesPaletteTool) {
-  assistant_state()->NotifyStatusChanged(mojom::VoiceInteractionState::RUNNING);
+  assistant_state()->NotifyStatusChanged(mojom::AssistantState::VISIBLE);
   prefs()->SetBoolean(chromeos::assistant::prefs::kAssistantEnabled, true);
   prefs()->SetBoolean(chromeos::assistant::prefs::kAssistantContextEnabled,
                       true);
@@ -168,7 +166,7 @@
   prefs()->SetBoolean(chromeos::assistant::prefs::kAssistantContextEnabled,
                       true);
 
-  // Test VoiceInteractionState changes.
+  // Test AssistantState changes.
   tool_->OnEnable();
 
   // Changing the state from RUNNING to STOPPED and back should not disable the
@@ -176,16 +174,15 @@
   EXPECT_CALL(*palette_tool_delegate_.get(),
               DisableTool(PaletteToolId::METALAYER))
       .Times(0);
-  assistant_state()->NotifyStatusChanged(mojom::VoiceInteractionState::STOPPED);
-  assistant_state()->NotifyStatusChanged(mojom::VoiceInteractionState::RUNNING);
+  assistant_state()->NotifyStatusChanged(mojom::AssistantState::READY);
+  assistant_state()->NotifyStatusChanged(mojom::AssistantState::VISIBLE);
   testing::Mock::VerifyAndClearExpectations(palette_tool_delegate_.get());
 
   // Changing the state to NOT_READY should disable the tool.
   EXPECT_CALL(*palette_tool_delegate_.get(),
               DisableTool(PaletteToolId::METALAYER))
       .Times(testing::AtLeast(1));
-  assistant_state()->NotifyStatusChanged(
-      mojom::VoiceInteractionState::NOT_READY);
+  assistant_state()->NotifyStatusChanged(mojom::AssistantState::NOT_READY);
   testing::Mock::VerifyAndClearExpectations(palette_tool_delegate_.get());
 }
 
diff --git a/ash/wm/desks/desk_mini_view.cc b/ash/wm/desks/desk_mini_view.cc
index 6051dae..dcde980 100644
--- a/ash/wm/desks/desk_mini_view.cc
+++ b/ash/wm/desks/desk_mini_view.cc
@@ -25,11 +25,10 @@
 
 constexpr int kLabelPreviewSpacing = 8;
 
-constexpr int kCloseButtonMargin = 4;
+constexpr int kCloseButtonMargin = 8;
 
-constexpr SkColor kActiveColor = SkColorSetA(SK_ColorWHITE, 0xCC);  // 80%
-
-constexpr SkColor kInactiveColor = SkColorSetA(SK_ColorWHITE, 0x33);  // 20%
+constexpr SkColor kActiveColor = SK_ColorWHITE;
+constexpr SkColor kInactiveColor = SK_ColorTRANSPARENT;
 
 constexpr SkColor kDraggedOverColor = SkColorSetARGB(0xFF, 0x5B, 0xBC, 0xFF);
 
diff --git a/ash/wm/desks/desk_preview_view.cc b/ash/wm/desks/desk_preview_view.cc
index c2117f67..d6f1b5e0 100644
--- a/ash/wm/desks/desk_preview_view.cc
+++ b/ash/wm/desks/desk_preview_view.cc
@@ -4,18 +4,24 @@
 
 #include "ash/wm/desks/desk_preview_view.h"
 
+#include <memory>
+
 #include "ash/multi_user/multi_user_window_manager_impl.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/wallpaper/wallpaper_base_view.h"
 #include "ash/wm/desks/desk_mini_view.h"
+#include "ash/wm/desks/desks_bar_item_border.h"
 #include "ash/wm/window_state.h"
 #include "base/containers/flat_map.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/layer_tree_owner.h"
+#include "ui/compositor/layer_type.h"
 #include "ui/compositor/paint_recorder.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/rounded_corners_f.h"
 #include "ui/gfx/skia_paint_util.h"
+#include "ui/views/border.h"
 
 namespace ash {
 
@@ -25,8 +31,8 @@
 // TODO(afakhry): Change the height to be dynamic according to the new specs.
 constexpr int kDeskPreviewHeight = 64;
 
-// The desk preview border size in dips.
-constexpr int kBorderSize = 2;
+// The corner radius of the border in dips.
+constexpr int kBorderCornerRadius = 6;
 
 // The rounded corner radii, also in dips.
 constexpr int kCornerRadius = 4;
@@ -194,7 +200,6 @@
 
 DeskPreviewView::DeskPreviewView(DeskMiniView* mini_view)
     : mini_view_(mini_view),
-      background_view_(new views::View),
       wallpaper_preview_(new DeskWallpaperPreview),
       desk_mirrored_contents_view_(new views::View),
       force_occlusion_tracker_visible_(
@@ -203,19 +208,14 @@
       shadow_delegate_(std::make_unique<ShadowRenderer>()) {
   DCHECK(mini_view_);
 
-  SetPaintToLayer(ui::LAYER_NOT_DRAWN);
+  SetPaintToLayer(ui::LAYER_TEXTURED);
+  layer()->SetFillsBoundsOpaquely(false);
   layer()->SetMasksToBounds(false);
 
   shadow_layer_.SetFillsBoundsOpaquely(false);
   layer()->Add(&shadow_layer_);
   shadow_layer_.set_delegate(shadow_delegate_.get());
 
-  background_view_->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
-  auto* background_layer = background_view_->layer();
-  background_layer->SetRoundedCornerRadius(kCornerRadii);
-  background_layer->SetIsFastRoundedCorner(true);
-  AddChildView(background_view_);
-
   wallpaper_preview_->SetPaintToLayer();
   auto* wallpaper_preview_layer = wallpaper_preview_->layer();
   wallpaper_preview_layer->SetFillsBoundsOpaquely(false);
@@ -231,6 +231,10 @@
   contents_view_layer->SetIsFastRoundedCorner(true);
   AddChildView(desk_mirrored_contents_view_);
 
+  auto border = std::make_unique<DesksBarItemBorder>(kBorderCornerRadius);
+  border_ptr_ = border.get();
+  SetBorder(std::move(border));
+
   RecreateDeskContentsMirrorLayers();
 }
 
@@ -242,7 +246,8 @@
 }
 
 void DeskPreviewView::SetBorderColor(SkColor color) {
-  background_view_->layer()->SetColor(color);
+  border_ptr_->set_color(color);
+  SchedulePaint();
 }
 
 void DeskPreviewView::RecreateDeskContentsMirrorLayers() {
@@ -278,11 +283,9 @@
 }
 
 void DeskPreviewView::Layout() {
-  gfx::Rect bounds = GetLocalBounds();
+  gfx::Rect bounds = GetContentsBounds();
   shadow_delegate_->set_bounds(bounds);
   shadow_layer_.SetBounds(shadow_delegate_->GetPaintedBounds());
-  background_view_->SetBoundsRect(bounds);
-  bounds.Inset(kBorderSize, kBorderSize);
   wallpaper_preview_->SetBoundsRect(bounds);
   desk_mirrored_contents_view_->SetBoundsRect(bounds);
 
diff --git a/ash/wm/desks/desk_preview_view.h b/ash/wm/desks/desk_preview_view.h
index c050123..244523f 100644
--- a/ash/wm/desks/desk_preview_view.h
+++ b/ash/wm/desks/desk_preview_view.h
@@ -15,6 +15,7 @@
 
 namespace ash {
 
+class DesksBarItemBorder;
 class DeskMiniView;
 class WallpaperBaseView;
 
@@ -49,17 +50,12 @@
 //        |      without the dimming and blur that overview mode adds.
 //        |
 //        |
-//     `background_view_`'s layer: A solid color layer to paint a background
-//      behind everything else, simulating a colored border around the view.
+//     `shadow_layer_`: A layer that paints a shadow behind this view.
 //
-// `background_view_` has the same size as this view, while `wallpaper_preview_`
-// and `desk_mirrored_contents_view_` are inset by an amount equal to the border
-// size from all sides (See `kBorderSize`).
-//
-// Note that both |background_view_| and |wallpaper_preview_| paint to layers
-// with rounded corners. In order to use the fast rounded corners implementation
-// we must make them sibling layers, rather than one being a descendant of the
-// other. Otherwise, this will trigger a render surface.
+// Note that both |desk_mirrored_contents_view_| and |wallpaper_preview_| paint
+// to layers with rounded corners. In order to use the fast rounded corners
+// implementation we must make them sibling layers, rather than one being a
+// descendant of the other. Otherwise, this will trigger a render surface.
 class DeskPreviewView : public views::View {
  public:
   explicit DeskPreviewView(DeskMiniView* mini_view);
@@ -83,10 +79,6 @@
 
   DeskMiniView* const mini_view_;
 
-  // A view to paint a background color behind the |wallpaper_preview_| to
-  // simulate a border. Owned by the views hierarchy.
-  views::View* background_view_;
-
   // A view that paints the wallpaper in the mini_view. It avoids the dimming
   // and blur overview mode adds to the original wallpaper. Owned by the views
   // hierarchy.
@@ -97,6 +89,10 @@
   // tree. Owned by the views hierarchy.
   views::View* desk_mirrored_contents_view_;
 
+  // Owned by this View via `View::border_`. This is just a convenient pointer
+  // to it.
+  DesksBarItemBorder* border_ptr_;
+
   // Owns the layer tree of the desk's contents mirrored layers.
   std::unique_ptr<ui::LayerTreeOwner> desk_mirrored_contents_layer_tree_owner_;
 
diff --git a/ash/wm/desks/desks_bar_item_border.cc b/ash/wm/desks/desks_bar_item_border.cc
new file mode 100644
index 0000000..437a53af
--- /dev/null
+++ b/ash/wm/desks/desks_bar_item_border.cc
@@ -0,0 +1,54 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/wm/desks/desks_bar_item_border.h"
+
+#include "cc/paint/paint_flags.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/views/view.h"
+
+namespace ash {
+
+namespace {
+
+// The desk preview border size and padding in dips.
+constexpr int kBorderSize = 2;
+constexpr int kBorderPadding = 2;
+
+}  // namespace
+
+DesksBarItemBorder::DesksBarItemBorder(int corner_radius)
+    : corner_radius_(corner_radius) {}
+
+void DesksBarItemBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
+  if (color_ == SK_ColorTRANSPARENT)
+    return;
+
+  cc::PaintFlags flags;
+  flags.setStrokeWidth(kBorderSize);
+  flags.setColor(color_);
+  flags.setStyle(cc::PaintFlags::kStroke_Style);
+  flags.setAntiAlias(true);
+
+  gfx::RectF bounds(view.GetLocalBounds());
+  // The following inset is needed for the rounded corners of the border to
+  // look correct. Otherwise, the borders will be painted at the edge of the
+  // view, resulting in this border looking chopped.
+  bounds.Inset(kBorderSize / 2, kBorderSize / 2);
+  canvas->DrawRoundRect(bounds, corner_radius_, flags);
+}
+
+gfx::Insets DesksBarItemBorder::GetInsets() const {
+  constexpr gfx::Insets kInsets{kBorderSize + kBorderPadding};
+  return kInsets;
+}
+
+gfx::Size DesksBarItemBorder::GetMinimumSize() const {
+  constexpr gfx::Size kMinSize{2 * (kBorderSize + kBorderPadding),
+                               2 * (kBorderSize + kBorderPadding)};
+  return kMinSize;
+}
+
+}  // namespace ash
diff --git a/ash/wm/desks/desks_bar_item_border.h b/ash/wm/desks/desks_bar_item_border.h
new file mode 100644
index 0000000..c192b6b21
--- /dev/null
+++ b/ash/wm/desks/desks_bar_item_border.h
@@ -0,0 +1,41 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_WM_DESKS_DESKS_BAR_ITEM_BORDER_H_
+#define ASH_WM_DESKS_DESKS_BAR_ITEM_BORDER_H_
+
+#include "base/macros.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/views/border.h"
+
+namespace ash {
+
+// Defines a border to be used on the views of the desks bar, such as the
+// DeskPreviewView and the NewDeskButton. This paints a border around the view
+// with an empty gap (padding) in-between, so that the border is more obvious
+// against white or light backgrounds. If a |SK_ColorTRANSPARENT| was provided,
+// it will paint nothing.
+class DesksBarItemBorder : public views::Border {
+ public:
+  explicit DesksBarItemBorder(int corner_radius);
+  ~DesksBarItemBorder() override = default;
+
+  void set_color(SkColor color) { color_ = color; }
+
+  // views::Border:
+  void Paint(const views::View& view, gfx::Canvas* canvas) override;
+  gfx::Insets GetInsets() const override;
+  gfx::Size GetMinimumSize() const override;
+
+ private:
+  const int corner_radius_;
+
+  SkColor color_ = SK_ColorTRANSPARENT;
+
+  DISALLOW_COPY_AND_ASSIGN(DesksBarItemBorder);
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_DESKS_DESKS_BAR_ITEM_BORDER_H_
diff --git a/ash/wm/desks/desks_bar_view.cc b/ash/wm/desks/desks_bar_view.cc
index aeb411d0a..6778abe 100644
--- a/ash/wm/desks/desks_bar_view.cc
+++ b/ash/wm/desks/desks_bar_view.cc
@@ -225,7 +225,7 @@
   if (mini_views_.empty())
     return;
 
-  constexpr int kMiniViewsSpacing = 8;
+  constexpr int kMiniViewsSpacing = 12;
   const gfx::Size mini_view_size = mini_views_[0]->GetPreferredSize();
   const int total_width =
       mini_views_.size() * (mini_view_size.width() + kMiniViewsSpacing) -
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index 09876c3..cc0e350 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -1354,7 +1354,7 @@
   const SkColor disabled_background_color =
       AshColorProvider::GetDisabledColor(background_color);
   EXPECT_TRUE(new_desk_button->GetEnabled());
-  EXPECT_EQ(background_color, new_desk_button->background()->get_color());
+  EXPECT_EQ(background_color, new_desk_button->GetBackgroundColorForTesting());
 
   const gfx::Point button_center =
       new_desk_button->GetBoundsInScreen().CenterPoint();
@@ -1362,7 +1362,7 @@
   event_generator->MoveMouseTo(button_center);
   event_generator->ClickLeftButton();
   EXPECT_TRUE(new_desk_button->GetEnabled());
-  EXPECT_EQ(background_color, new_desk_button->background()->get_color());
+  EXPECT_EQ(background_color, new_desk_button->GetBackgroundColorForTesting());
 
   // Tests that adding desks until we reach the desks limit should change the
   // state and color of the new desk button.
@@ -1374,7 +1374,7 @@
   }
   EXPECT_FALSE(new_desk_button->GetEnabled());
   EXPECT_EQ(disabled_background_color,
-            new_desk_button->background()->get_color());
+            new_desk_button->GetBackgroundColorForTesting());
 }
 
 class TabletModeDesksTest : public DesksTest {
diff --git a/ash/wm/desks/new_desk_button.cc b/ash/wm/desks/new_desk_button.cc
index e55febf..f1158b4 100644
--- a/ash/wm/desks/new_desk_button.cc
+++ b/ash/wm/desks/new_desk_button.cc
@@ -4,12 +4,14 @@
 
 #include "ash/wm/desks/new_desk_button.h"
 
+#include <memory>
 #include <utility>
 
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
+#include "ash/wm/desks/desks_bar_item_border.h"
 #include "ash/wm/desks/desks_bar_view.h"
 #include "ash/wm/desks/desks_controller.h"
 #include "ash/wm/desks/desks_util.h"
@@ -18,6 +20,7 @@
 #include "ash/wm/overview/overview_session.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/canvas.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/animation/ink_drop_impl.h"
@@ -45,10 +48,6 @@
 constexpr SkColor kDisabledTextAndIconColor =
     SkColorSetA(kTextAndIconColor, 0x61);
 
-// The color of the highlight when this button is selected via
-// tabbing.
-constexpr int kHighlightThicknessDp = 2;
-
 }  // namespace
 
 NewDeskButton::NewDeskButton(views::ButtonListener* listener)
@@ -69,6 +68,11 @@
   set_has_ink_drop_action_on_click(true);
   set_ink_drop_visible_opacity(kInkDropVisibleOpacity);
   SetFocusPainter(nullptr);
+
+  auto border = std::make_unique<DesksBarItemBorder>(kCornerRadius);
+  border_ptr_ = border.get();
+  SetBorder(std::move(border));
+
   UpdateButtonState();
   UpdateBorderState();
 }
@@ -85,14 +89,12 @@
   }
   SetEnabled(enabled);
 
-  const SkColor background_color =
-      AshColorProvider::Get()->GetControlsLayerColor(
-          AshColorProvider::ControlsLayerType::kInactiveControlBackground,
-          AshColorProvider::AshColorMode::kDark);
-  const SkColor disabled_background_color =
-      AshColorProvider::GetDisabledColor(background_color);
-  SetBackground(views::CreateRoundedRectBackground(
-      enabled ? background_color : disabled_background_color, kCornerRadius));
+  background_color_ = AshColorProvider::Get()->GetControlsLayerColor(
+      AshColorProvider::ControlsLayerType::kInactiveControlBackground,
+      AshColorProvider::AshColorMode::kDark);
+  if (!enabled)
+    background_color_ = AshColorProvider::GetDisabledColor(background_color_);
+  SchedulePaint();
 }
 
 void NewDeskButton::OnButtonPressed() {
@@ -107,6 +109,15 @@
   return "NewDeskButton";
 }
 
+void NewDeskButton::OnPaintBackground(gfx::Canvas* canvas) {
+  // Paint a background that takes into account this view's insets.
+  cc::PaintFlags flags;
+  flags.setAntiAlias(true);
+  flags.setStyle(cc::PaintFlags::kFill_Style);
+  flags.setColor(background_color_);
+  canvas->DrawRoundRect(gfx::RectF(GetContentsBounds()), kCornerRadius, flags);
+}
+
 std::unique_ptr<views::InkDrop> NewDeskButton::CreateInkDrop() {
   auto ink_drop = CreateDefaultFloodFillInkDropImpl();
   ink_drop->SetShowHighlightOnHover(false);
@@ -126,7 +137,7 @@
 }
 
 std::unique_ptr<views::InkDropMask> NewDeskButton::CreateInkDropMask() const {
-  return std::make_unique<views::RoundRectInkDropMask>(size(), gfx::Insets(),
+  return std::make_unique<views::RoundRectInkDropMask>(size(), GetInsets(),
                                                        kCornerRadius);
 }
 
@@ -168,16 +179,12 @@
 }
 
 void NewDeskButton::UpdateBorderState() {
-  if (IsViewHighlighted() && DesksController::Get()->CanCreateDesks()) {
-    SetBorder(views::CreateRoundedRectBorder(
-        kHighlightThicknessDp, kCornerRadius,
-        GetNativeTheme()->GetSystemColor(
-            ui::NativeTheme::kColorId_FocusedBorderColor)));
-  } else {
-    // Use an empty border when this view is not highlighted otherwise the text
-    // will shift when unhighlighted.
-    SetBorder(views::CreateEmptyBorder(gfx::Insets(kHighlightThicknessDp)));
-  }
+  border_ptr_->set_color(
+      (IsViewHighlighted() && DesksController::Get()->CanCreateDesks())
+          ? GetNativeTheme()->GetSystemColor(
+                ui::NativeTheme::kColorId_FocusedBorderColor)
+          : SK_ColorTRANSPARENT);
+  SchedulePaint();
 }
 
 }  // namespace ash
diff --git a/ash/wm/desks/new_desk_button.h b/ash/wm/desks/new_desk_button.h
index 780f78a..c72113f 100644
--- a/ash/wm/desks/new_desk_button.h
+++ b/ash/wm/desks/new_desk_button.h
@@ -14,6 +14,8 @@
 
 namespace ash {
 
+class DesksBarItemBorder;
+
 // A button view that shows up in the top-right corner of the screen when
 // overview mode is on, which is used to create a new virtual desk.
 class ASH_EXPORT NewDeskButton
@@ -30,6 +32,7 @@
 
   // LabelButton:
   const char* GetClassName() const override;
+  void OnPaintBackground(gfx::Canvas* canvas) override;
   std::unique_ptr<views::InkDrop> CreateInkDrop() override;
   std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
       const override;
@@ -47,9 +50,17 @@
   bool OnViewHighlighted() override;
   void OnViewUnhighlighted() override;
 
+  SkColor GetBackgroundColorForTesting() const { return background_color_; }
+
  private:
   void UpdateBorderState();
 
+  // Owned by this View via `View::border_`. This is just a convenient pointer
+  // to it.
+  DesksBarItemBorder* border_ptr_;
+
+  SkColor background_color_;
+
   DISALLOW_COPY_AND_ASSIGN(NewDeskButton);
 };
 
diff --git a/base/callback_helpers.h b/base/callback_helpers.h
index 1db35ee..e74f5848 100644
--- a/base/callback_helpers.h
+++ b/base/callback_helpers.h
@@ -114,6 +114,8 @@
   // Releases the Closure without calling.
   OnceClosure Release() WARN_UNUSED_RESULT;
 
+  bool is_null() const { return closure_.is_null(); }
+
  private:
   OnceClosure closure_;
 
diff --git a/build/android/BUILD.gn b/build/android/BUILD.gn
index e258826..957ebb8 100644
--- a/build/android/BUILD.gn
+++ b/build/android/BUILD.gn
@@ -85,6 +85,7 @@
     "${android_sdk_build_tools}/lib64/libc++.so",
     "${android_sdk_build_tools}/split-select",
     "${android_sdk_root}/platform-tools/adb",
+    "//third_party/android_build_tools/bundletool/bundletool-all-0.10.3.jar",
   ]
   data_deps = [
     ":devil_chromium_py",
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index afa2ee9..c94c6e6 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -796,8 +796,8 @@
       }
     }
 
-    if (defined(invoker.command_line_args)) {
-      executable_args += invoker.command_line_args
+    if (defined(invoker.extra_args)) {
+      executable_args += invoker.extra_args
     }
   }
 }
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index c99d782..57e1dae 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -3567,10 +3567,10 @@
   #   The following args are optional:
   #   apk_under_test: The target being tested.
   #   additional_apks: Additional targets to install on device.
-  #   command_line_args: Command line arguments to set for APK under test.
   #   data: List of runtime data file dependencies.
   #   data_deps: List of non-linked dependencies.
   #   deps: List of private dependencies.
+  #   extra_args: Extra arguments set for test runner.
   #   ignore_all_data_deps: Don't build data_deps and additional_apks.
   #   modules: Extra dynamic feature modules to install for test target. Can
   #     only be used if |apk_under_test| is an Android app bundle.
@@ -3613,10 +3613,10 @@
                                [
                                  "additional_apks",
                                  "apk_under_test",
-                                 "command_line_args",
                                  "data",
                                  "data_deps",
                                  "deps",
+                                 "extra_args",
                                  "ignore_all_data_deps",
                                  "modules",
                                  "proguard_enabled",
@@ -3821,10 +3821,10 @@
                              [
                                "additional_apks",
                                "apk_under_test",
-                               "command_line_args",
                                "data",
                                "data_deps",
                                "deps",
+                               "extra_args",
                                "ignore_all_data_deps",
                                "modules",
                                "never_incremental",
@@ -4770,9 +4770,6 @@
       outputs = [
         _bundle_path,
       ]
-      data = [
-        _bundle_path,
-      ]
       deps = _all_create_module_targets + [ ":$_build_config_target" ]
       args = [
         "--out-bundle=$_rebased_bundle_path",
@@ -4859,6 +4856,7 @@
         _bundle_wrapper_script_path,
         _android_aapt2_path,
         _keystore_path,
+        _bundle_path,
       ]
       data_deps = [
         "//build/android:bundle_wrapper_script_py",
@@ -4928,6 +4926,9 @@
       outputs = [
         _apks_path,
       ]
+      data = [
+        _apks_path,
+      ]
       args = [
         "--bundle",
         _rebased_bundle_path,
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 6739ae8..e09be88 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8903107792788060944
\ No newline at end of file
+8902647923806574208
\ No newline at end of file
diff --git a/build/toolchain/win/setup_toolchain.py b/build/toolchain/win/setup_toolchain.py
index ef8aeda5..9ee69df7 100644
--- a/build/toolchain/win/setup_toolchain.py
+++ b/build/toolchain/win/setup_toolchain.py
@@ -28,15 +28,21 @@
   """Extracts environment variables required for the toolchain to run from
   a textual dump output by the cmd.exe 'set' command."""
   envvars_to_save = (
+      'cipd_cache_dir', # needed by vpython
+      'homedrive', # needed by vpython
+      'homepath', # needed by vpython
       'goma_.*', # TODO(scottmg): This is ugly, but needed for goma.
       'include',
       'lib',
       'libpath',
+      'luci_context', # needed by vpython
       'path',
       'pathext',
       'systemroot',
       'temp',
       'tmp',
+      'userprofile', # needed by vpython
+      'vpython_virtualenv_root' # needed by vpython
       )
   env = {}
   # This occasionally happens and leads to misleading SYSTEMROOT error messages
diff --git a/cc/metrics/frame_sequence_tracker.cc b/cc/metrics/frame_sequence_tracker.cc
index 89b1012..31dce1de 100644
--- a/cc/metrics/frame_sequence_tracker.cc
+++ b/cc/metrics/frame_sequence_tracker.cc
@@ -19,7 +19,7 @@
 
 const char* const FrameSequenceTracker::kFrameSequenceTrackerTypeNames[] = {
     "CompositorAnimation", "MainThreadAnimation", "PinchZoom", "RAF",
-    "TouchScroll",         "WheelScroll",         ""};
+    "TouchScroll",         "WheelScroll",         "Universal", ""};
 
 namespace {
 
@@ -69,7 +69,9 @@
 FrameSequenceTrackerCollection::FrameSequenceTrackerCollection(
     CompositorFrameReportingController* compositor_frame_reporting_controller)
     : compositor_frame_reporting_controller_(
-          compositor_frame_reporting_controller) {}
+          compositor_frame_reporting_controller) {
+  StartSequence(FrameSequenceTrackerType::kUniversal);
+}
 
 FrameSequenceTrackerCollection::~FrameSequenceTrackerCollection() {
   frame_trackers_.clear();
@@ -106,6 +108,7 @@
 void FrameSequenceTrackerCollection::ClearAll() {
   frame_trackers_.clear();
   removal_trackers_.clear();
+  StartSequence(FrameSequenceTrackerType::kUniversal);
 }
 
 void FrameSequenceTrackerCollection::NotifyBeginImplFrame(
diff --git a/cc/metrics/frame_sequence_tracker.h b/cc/metrics/frame_sequence_tracker.h
index 3d56a1d..40785e2 100644
--- a/cc/metrics/frame_sequence_tracker.h
+++ b/cc/metrics/frame_sequence_tracker.h
@@ -38,6 +38,7 @@
   kRAF,
   kTouchScroll,
   kWheelScroll,
+  kUniversal,
   kMaxType
 };
 
diff --git a/cc/metrics/frame_sequence_tracker_unittest.cc b/cc/metrics/frame_sequence_tracker_unittest.cc
index 41fa336..a597e48 100644
--- a/cc/metrics/frame_sequence_tracker_unittest.cc
+++ b/cc/metrics/frame_sequence_tracker_unittest.cc
@@ -76,13 +76,21 @@
     return ++frame_token;
   }
 
+  // Check whether a type of tracker exists in |frame_trackers_| or not.
+  bool TrackerExists(FrameSequenceTrackerType type) const {
+    return collection_.frame_trackers_.contains(type);
+  }
+
   void TestNotifyFramePresented() {
     collection_.StartSequence(FrameSequenceTrackerType::kCompositorAnimation);
     collection_.StartSequence(FrameSequenceTrackerType::kMainThreadAnimation);
-    EXPECT_EQ(collection_.frame_trackers_.size(), 3u);
+    // The kTouchScroll tracker is created in the test constructor, and the
+    // kUniversal tracker is created in the FrameSequenceTrackerCollection
+    // constructor.
+    EXPECT_EQ(collection_.frame_trackers_.size(), 4u);
 
     collection_.StopSequence(kCompositorAnimation);
-    EXPECT_EQ(collection_.frame_trackers_.size(), 2u);
+    EXPECT_EQ(collection_.frame_trackers_.size(), 3u);
     EXPECT_TRUE(collection_.frame_trackers_.contains(
         FrameSequenceTrackerType::kMainThreadAnimation));
     EXPECT_TRUE(collection_.frame_trackers_.contains(
@@ -142,6 +150,17 @@
                                 viz::BeginFrameAck(args_2, true), args_1);
 }
 
+TEST_F(FrameSequenceTrackerTest, UniversalTrackerCreation) {
+  // The universal tracker should have been created when the |collection_| is
+  // created.
+  EXPECT_TRUE(TrackerExists(FrameSequenceTrackerType::kUniversal));
+}
+
+TEST_F(FrameSequenceTrackerTest, UniversalTrackerExistsAfterClearAll) {
+  collection_.ClearAll();
+  EXPECT_TRUE(TrackerExists(FrameSequenceTrackerType::kUniversal));
+}
+
 TEST_F(FrameSequenceTrackerTest, TestNotifyFramePresented) {
   TestNotifyFramePresented();
 }
diff --git a/cc/test/fake_paint_image_generator.cc b/cc/test/fake_paint_image_generator.cc
index 728a58c..29f19913 100644
--- a/cc/test/fake_paint_image_generator.cc
+++ b/cc/test/fake_paint_image_generator.cc
@@ -113,4 +113,8 @@
   return PaintImageGenerator::GetSupportedDecodeSize(requested_size);
 }
 
+PaintImage::ImageType FakePaintImageGenerator::GetImageType() const {
+  return image_type_;
+}
+
 }  // namespace cc
diff --git a/cc/test/fake_paint_image_generator.h b/cc/test/fake_paint_image_generator.h
index 003afdf..6a51836c 100644
--- a/cc/test/fake_paint_image_generator.h
+++ b/cc/test/fake_paint_image_generator.h
@@ -50,6 +50,7 @@
                       size_t frame_index,
                       uint32_t lazy_pixel_ref) override;
   SkISize GetSupportedDecodeSize(const SkISize& requested_size) const override;
+  PaintImage::ImageType GetImageType() const override;
 
   const base::flat_map<size_t, int>& frames_decoded() const {
     return frames_decoded_count_;
@@ -63,12 +64,16 @@
   void SetEligibleForAcceleratedDecoding() {
     is_eligible_for_accelerated_decode_ = true;
   }
+  void SetImageType(PaintImage::ImageType image_type) {
+    image_type_ = image_type;
+  }
 
  private:
   std::vector<uint8_t> image_backing_memory_;
   SkPixmap image_pixmap_;
   base::flat_map<size_t, int> frames_decoded_count_;
   std::vector<SkISize> supported_sizes_;
+  PaintImage::ImageType image_type_ = PaintImage::ImageType::kInvalid;
   std::vector<SkImageInfo> decode_infos_;
   bool is_yuv_ = false;
   SkYUVASizeInfo yuva_size_info_;
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index 461927b..d8750a1 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -961,6 +961,20 @@
       persistent_cache_(PersistentCache::NO_AUTO_EVICT),
       max_working_set_bytes_(max_working_set_bytes),
       max_working_set_items_(kMaxItemsInWorkingSet) {
+  // Note that to compute |allow_accelerated_jpeg_decodes_| and
+  // |allow_accelerated_webp_decodes_|, the last thing we check is the feature
+  // flag. That's because we want to ensure that we're in OOP-R mode and the
+  // hardware decoder supports the image type so that finch experiments
+  // involving hardware decode acceleration only count users in that
+  // population (both in the 'control' and the 'enabled' groups).
+  allow_accelerated_jpeg_decodes_ =
+      use_transfer_cache &&
+      context_->ContextSupport()->IsJpegDecodeAccelerationSupported() &&
+      base::FeatureList::IsEnabled(features::kVaapiJpegImageDecodeAcceleration);
+  allow_accelerated_webp_decodes_ =
+      use_transfer_cache &&
+      context_->ContextSupport()->IsWebPDecodeAccelerationSupported() &&
+      base::FeatureList::IsEnabled(features::kVaapiWebPImageDecodeAcceleration);
   // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
   // Don't register a dump provider in these cases.
   if (base::ThreadTaskRunnerHandle::IsSet()) {
@@ -2265,9 +2279,6 @@
   //   of this, we return a pointer to the contiguous data (as |encoded_data|)
   //   so that we can re-use it later (when requesting the image decode).
   //
-  // TODO(crbug.com/953363): ideally, we can make the hardware decoder support
-  // decision without requiring contiguous data.
-  //
   // TODO(crbug.com/953367): currently, we don't support scaling with hardware
   // decode acceleration. Note that it's still okay for the image to be
   // downscaled by Skia using the GPU.
@@ -2276,15 +2287,17 @@
   // decoded data, but for accelerated decodes we won't know until the driver
   // gives us the result in the GPU process. Figure out what to do.
   bool do_hardware_accelerated_decode = false;
-  if ((base::FeatureList::IsEnabled(
-           features::kVaapiJpegImageDecodeAcceleration) ||
-       base::FeatureList::IsEnabled(
-           features::kVaapiWebPImageDecodeAcceleration)) &&
-      allow_hardware_decode && mode == DecodedDataMode::kTransferCache &&
-      upload_scale_mip_level == 0 &&
+  if ((allow_accelerated_jpeg_decodes_ || allow_accelerated_webp_decodes_) &&
+      allow_hardware_decode && upload_scale_mip_level == 0 &&
       draw_image.paint_image().IsEligibleForAcceleratedDecoding() &&
       draw_image.paint_image().color_space() &&
       draw_image.paint_image().color_space()->isSRGB()) {
+    DCHECK_EQ(mode, DecodedDataMode::kTransferCache);
+    // TODO(crbug.com/995149): we should not require the encoded data to figure
+    // out if the hardware decoder supports the image. Instead, we should pass
+    // only the necessary attributes to CanDecodeWithHardwareAcceleration().
+    // This is important because extracting the encoded data may require a copy
+    // if the data is not contiguous.
     sk_sp<SkData> tmp_encoded_data =
         draw_image.paint_image().GetSkImage()
             ? draw_image.paint_image().GetSkImage()->refEncodedData()
@@ -2293,7 +2306,13 @@
         context_->ContextSupport()->CanDecodeWithHardwareAcceleration(
             base::make_span<const uint8_t>(tmp_encoded_data->bytes(),
                                            tmp_encoded_data->size()))) {
-      do_hardware_accelerated_decode = true;
+      const bool is_jpeg = (draw_image.paint_image().GetImageType() ==
+                            PaintImage::ImageType::kJPEG);
+      const bool is_webp = (draw_image.paint_image().GetImageType() ==
+                            PaintImage::ImageType::kWEBP);
+      do_hardware_accelerated_decode =
+          (is_jpeg && allow_accelerated_jpeg_decodes_) ||
+          (is_webp && allow_accelerated_webp_decodes_);
       DCHECK(encoded_data);
       *encoded_data = std::move(tmp_encoded_data);
     }
diff --git a/cc/tiles/gpu_image_decode_cache.h b/cc/tiles/gpu_image_decode_cache.h
index 466ee2d..2f53534 100644
--- a/cc/tiles/gpu_image_decode_cache.h
+++ b/cc/tiles/gpu_image_decode_cache.h
@@ -701,6 +701,8 @@
   viz::RasterContextProvider* context_;
   int max_texture_size_ = 0;
   const PaintImage::GeneratorClientId generator_client_id_;
+  bool allow_accelerated_jpeg_decodes_ = false;
+  bool allow_accelerated_webp_decodes_ = false;
 
   // All members below this point must only be accessed while holding |lock_|.
   // The exception are const members like |normal_max_cache_bytes_| that can
diff --git a/cc/tiles/gpu_image_decode_cache_perftest.cc b/cc/tiles/gpu_image_decode_cache_perftest.cc
index 258bec1..8b1d4239 100644
--- a/cc/tiles/gpu_image_decode_cache_perftest.cc
+++ b/cc/tiles/gpu_image_decode_cache_perftest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
 #include <vector>
 
 #include "base/timer/lap_timer.h"
@@ -48,17 +49,14 @@
         context_provider_(
             base::MakeRefCounted<viz::TestInProcessContextProvider>(
                 UseTransferCache(),
-                false /* support_locking */)),
-        cache_(context_provider_.get(),
-               UseTransferCache(),
-               kRGBA_8888_SkColorType,
-               kCacheSize,
-               MaxTextureSize(),
-               PaintImage::kDefaultGeneratorClientId) {
-    // Initializing context here is ok because image decode cache does not use
-    // context provider in its constructor.
+                false /* support_locking */)) {}
+
+  void SetUp() override {
     gpu::ContextResult result = context_provider_->BindToCurrentThread();
-    DCHECK_EQ(result, gpu::ContextResult::kSuccess);
+    ASSERT_EQ(result, gpu::ContextResult::kSuccess);
+    cache_ = std::make_unique<GpuImageDecodeCache>(
+        context_provider_.get(), UseTransferCache(), kRGBA_8888_SkColorType,
+        kCacheSize, MaxTextureSize(), PaintImage::kDefaultGeneratorClientId);
   }
 
  protected:
@@ -97,7 +95,7 @@
 
   base::LapTimer timer_;
   scoped_refptr<viz::TestInProcessContextProvider> context_provider_;
-  GpuImageDecodeCache cache_;
+  std::unique_ptr<GpuImageDecodeCache> cache_;
 };
 
 INSTANTIATE_TEST_SUITE_P(P,
@@ -118,8 +116,8 @@
         CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u,
         gfx::ColorSpace::CreateXYZD50());
 
-    DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image);
-    cache_.DrawWithImageFinished(image, decoded_image);
+    DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image);
+    cache_->DrawWithImageFinished(image, decoded_image);
     timer_.NextLap();
   } while (!timer_.HasTimeLimitExpired());
 
@@ -150,7 +148,7 @@
         SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality,
         CreateMatrix(SkSize::Make(0.6f, 0.6f)), 0u, gfx::ColorSpace());
 
-    DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image);
+    DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image);
 
     if (GetParam() == TestMode::kGpu) {
       SkPaint paint;
@@ -161,7 +159,7 @@
       surface->flush();
     }
 
-    cache_.DrawWithImageFinished(image, decoded_image);
+    cache_->DrawWithImageFinished(image, decoded_image);
     timer_.NextLap();
   } while (!timer_.HasTimeLimitExpired());
 
@@ -180,12 +178,12 @@
       CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u,
       gfx::ColorSpace::CreateXYZD50());
 
-  DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image);
-  cache_.DrawWithImageFinished(image, decoded_image);
+  DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image);
+  cache_->DrawWithImageFinished(image, decoded_image);
 
   do {
-    decoded_image = cache_.GetDecodedImageForDraw(image);
-    cache_.DrawWithImageFinished(image, decoded_image);
+    decoded_image = cache_->GetDecodedImageForDraw(image);
+    cache_->DrawWithImageFinished(image, decoded_image);
     timer_.NextLap();
   } while (!timer_.HasTimeLimitExpired());
 
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc
index 0c641903..d60b3a3 100644
--- a/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -5,7 +5,9 @@
 #include "cc/tiles/gpu_image_decode_cache.h"
 
 #include <memory>
+#include <vector>
 
+#include "base/feature_list.h"
 #include "base/test/scoped_feature_list.h"
 #include "cc/paint/draw_image.h"
 #include "cc/paint/image_transfer_cache_entry.h"
@@ -172,6 +174,14 @@
     transfer_cache_helper_->DeleteEntryDirect(MakeEntryKey(type, id));
   }
 
+  bool IsJpegDecodeAccelerationSupported() const override {
+    return advertise_accelerated_decoding_;
+  }
+
+  bool IsWebPDecodeAccelerationSupported() const override {
+    return advertise_accelerated_decoding_;
+  }
+
   bool CanDecodeWithHardwareAcceleration(
       base::span<const uint8_t> encoded_data) const override {
     return advertise_accelerated_decoding_;
@@ -319,14 +329,21 @@
           std::tuple<SkColorType,
                      bool /* use_transfer_cache */,
                      bool /* do_yuv_decode */,
+                     bool /* allow_accelerated_jpeg_decoding */,
+                     bool /* allow_accelerated_webp_decoding */,
                      bool /* advertise_accelerated_decoding */>> {
  public:
   void SetUp() override {
-    advertise_accelerated_decoding_ = std::get<3>(GetParam());
-    if (advertise_accelerated_decoding_) {
-      feature_list_.InitAndEnableFeature(
-          features::kVaapiJpegImageDecodeAcceleration);
-    }
+    std::vector<base::Feature> enabled_features;
+    allow_accelerated_jpeg_decoding_ = std::get<3>(GetParam());
+    if (allow_accelerated_jpeg_decoding_)
+      enabled_features.push_back(features::kVaapiJpegImageDecodeAcceleration);
+    allow_accelerated_webp_decoding_ = std::get<4>(GetParam());
+    if (allow_accelerated_webp_decoding_)
+      enabled_features.push_back(features::kVaapiWebPImageDecodeAcceleration);
+    feature_list_.InitWithFeatures(enabled_features,
+                                   {} /* disabled_features */);
+    advertise_accelerated_decoding_ = std::get<5>(GetParam());
     context_provider_ = GPUImageDecodeTestMockContextProvider::Create(
         &discardable_manager_, &transfer_cache_helper_,
         advertise_accelerated_decoding_);
@@ -556,6 +573,8 @@
   bool use_transfer_cache_;
   SkColorType color_type_;
   bool do_yuv_decode_;
+  bool allow_accelerated_jpeg_decoding_;
+  bool allow_accelerated_webp_decoding_;
   bool advertise_accelerated_decoding_;
   int max_texture_size_ = 0;
 };
@@ -2912,6 +2931,8 @@
         testing::ValuesIn(test_color_types),
         testing::ValuesIn(false_array) /* use_transfer_cache */,
         testing::Bool() /* do_yuv_decode */,
+        testing::ValuesIn(false_array) /* allow_accelerated_jpeg_decoding */,
+        testing::ValuesIn(false_array) /* allow_accelerated_webp_decoding */,
         testing::ValuesIn(false_array) /* advertise_accelerated_decoding */));
 
 INSTANTIATE_TEST_SUITE_P(
@@ -2921,6 +2942,8 @@
         testing::ValuesIn(test_color_types),
         testing::ValuesIn(true_array) /* use_transfer_cache */,
         testing::Bool() /* do_yuv_decode */,
+        testing::ValuesIn(false_array) /* allow_accelerated_jpeg_decoding */,
+        testing::ValuesIn(false_array) /* allow_accelerated_webp_decoding */,
         testing::ValuesIn(false_array) /* advertise_accelerated_decoding */));
 
 class GpuImageDecodeCacheWithAcceleratedDecodesTest
@@ -2929,7 +2952,8 @@
   PaintImage CreatePaintImageForDecodeAcceleration(
       const gfx::Size& size,
       sk_sp<SkColorSpace> color_space = nullptr,
-      bool is_eligible_for_accelerated_decoding = true) {
+      bool is_eligible_for_accelerated_decoding = true,
+      PaintImage::ImageType image_type = PaintImage::ImageType::kJPEG) {
     SkImageInfo info =
         SkImageInfo::Make(size.width(), size.height(), color_type_,
                           kPremul_SkAlphaType, color_space);
@@ -2942,6 +2966,7 @@
     }
     if (is_eligible_for_accelerated_decoding)
       generator->SetEligibleForAcceleratedDecoding();
+    generator->SetImageType(image_type);
     PaintImage image = PaintImageBuilder::WithDefault()
                            .set_id(PaintImage::GetNextId())
                            .set_paint_image_generator(generator)
@@ -3227,8 +3252,112 @@
         testing::ValuesIn(test_color_types),
         testing::ValuesIn(true_array) /* use_transfer_cache */,
         testing::Bool() /* do_yuv_decode */,
+        testing::ValuesIn(true_array) /* allow_accelerated_jpeg_decoding */,
+        testing::ValuesIn(true_array) /* allow_accelerated_webp_decoding */,
         testing::ValuesIn(true_array) /* advertise_accelerated_decoding */));
 
+class GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest
+    : public GpuImageDecodeCacheWithAcceleratedDecodesTest {};
+
+TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest,
+       RequestAcceleratedDecodeSuccessfully) {
+  auto cache = CreateCache();
+  const gfx::Size image_size = GetNormalImageSize();
+  const SkFilterQuality quality = kHigh_SkFilterQuality;
+  const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateSRGB();
+  ASSERT_TRUE(target_color_space.IsValid());
+
+  // Try a JPEG image.
+  const PaintImage jpeg_image = CreatePaintImageForDecodeAcceleration(
+      image_size, SkColorSpace::MakeSRGB(),
+      true /* is_eligible_for_accelerated_decoding */,
+      PaintImage::ImageType::kJPEG);
+  DrawImage jpeg_draw_image(
+      jpeg_image, SkIRect::MakeWH(jpeg_image.width(), jpeg_image.height()),
+      quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
+      PaintImage::kDefaultFrameIndex, target_color_space);
+  ImageDecodeCache::TaskResult jpeg_task = cache->GetTaskForImageAndRef(
+      jpeg_draw_image, ImageDecodeCache::TracingInfo());
+  EXPECT_TRUE(jpeg_task.need_unref);
+  ASSERT_TRUE(jpeg_task.task);
+  // If the hardware decoder claims support for the image (i.e.,
+  // |advertise_accelerated_decoding_| is true) and the feature flag for the
+  // image type is on (i.e., |allow_accelerated_jpeg_decoding_| is true), we
+  // should expect hardware acceleration. In that path, there is only an upload
+  // task without a decode dependency since the decode will be done in the GPU
+  // process. In the alternative path (software decoding), the upload task
+  // depends on a decode task that runs in the renderer.
+  if (advertise_accelerated_decoding_ && allow_accelerated_jpeg_decoding_) {
+    ASSERT_TRUE(jpeg_task.task->dependencies().empty());
+    EXPECT_CALL(*raster_implementation(),
+                DoScheduleImageDecode(image_size, _, gfx::ColorSpace(), _))
+        .Times(1);
+  } else {
+    ASSERT_EQ(jpeg_task.task->dependencies().size(), 1u);
+    ASSERT_TRUE(jpeg_task.task->dependencies()[0]);
+    TestTileTaskRunner::ProcessTask(jpeg_task.task->dependencies()[0].get());
+  }
+  TestTileTaskRunner::ProcessTask(jpeg_task.task.get());
+  testing::Mock::VerifyAndClearExpectations(raster_implementation());
+  cache->UnrefImage(jpeg_draw_image);
+
+  // Try a WebP image.
+  const PaintImage webp_image = CreatePaintImageForDecodeAcceleration(
+      image_size, SkColorSpace::MakeSRGB(),
+      true /* is_eligible_for_accelerated_decoding */,
+      PaintImage::ImageType::kWEBP);
+  DrawImage webp_draw_image(
+      webp_image, SkIRect::MakeWH(webp_image.width(), webp_image.height()),
+      quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
+      PaintImage::kDefaultFrameIndex, target_color_space);
+  ImageDecodeCache::TaskResult webp_task = cache->GetTaskForImageAndRef(
+      webp_draw_image, ImageDecodeCache::TracingInfo());
+  EXPECT_TRUE(webp_task.need_unref);
+  ASSERT_TRUE(webp_task.task);
+  if (advertise_accelerated_decoding_ && allow_accelerated_webp_decoding_) {
+    ASSERT_TRUE(webp_task.task->dependencies().empty());
+    EXPECT_CALL(*raster_implementation(),
+                DoScheduleImageDecode(image_size, _, gfx::ColorSpace(), _))
+        .Times(1);
+  } else {
+    ASSERT_EQ(webp_task.task->dependencies().size(), 1u);
+    ASSERT_TRUE(webp_task.task->dependencies()[0]);
+    TestTileTaskRunner::ProcessTask(webp_task.task->dependencies()[0].get());
+  }
+  TestTileTaskRunner::ProcessTask(webp_task.task.get());
+  testing::Mock::VerifyAndClearExpectations(raster_implementation());
+  cache->UnrefImage(webp_draw_image);
+
+  // Try a PNG image (which should not be hardware accelerated).
+  const PaintImage png_image = CreatePaintImageForDecodeAcceleration(
+      image_size, SkColorSpace::MakeSRGB(),
+      true /* is_eligible_for_accelerated_decoding */,
+      PaintImage::ImageType::kPNG);
+  DrawImage png_draw_image(
+      png_image, SkIRect::MakeWH(jpeg_image.width(), jpeg_image.height()),
+      quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
+      PaintImage::kDefaultFrameIndex, target_color_space);
+  ImageDecodeCache::TaskResult png_task = cache->GetTaskForImageAndRef(
+      png_draw_image, ImageDecodeCache::TracingInfo());
+  EXPECT_TRUE(png_task.need_unref);
+  ASSERT_TRUE(png_task.task);
+  ASSERT_EQ(png_task.task->dependencies().size(), 1u);
+  ASSERT_TRUE(png_task.task->dependencies()[0]);
+  TestTileTaskRunner::ProcessTask(png_task.task->dependencies()[0].get());
+  TestTileTaskRunner::ProcessTask(png_task.task.get());
+  cache->UnrefImage(png_draw_image);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    GpuImageDecodeCacheTestsOOPR,
+    GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest,
+    testing::Combine(testing::Values(kN32_SkColorType),
+                     testing::ValuesIn(true_array) /* use_transfer_cache */,
+                     testing::Bool() /* do_yuv_decode */,
+                     testing::Bool() /* allow_accelerated_jpeg_decoding */,
+                     testing::Bool() /* allow_accelerated_webp_decoding */,
+                     testing::Bool() /* advertise_accelerated_decoding */));
+
 #undef EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE
 #undef EXPECT_FALSE_IF_NOT_USING_TRANSFER_CACHE
 
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 962b023a..e7ca5dc 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -576,8 +576,8 @@
   }
 
   viz::BeginFrameArgs begin_frame_args(viz::BeginFrameArgs::Create(
-      BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
-      frame_begin_time, base::TimeTicks(),
+      BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId,
+      begin_frame_sequence_number_++, frame_begin_time, base::TimeTicks(),
       viz::BeginFrameArgs::DefaultInterval(), viz::BeginFrameArgs::NORMAL));
 
   // Start the impl frame.
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index 320688e..fc5a266 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -201,6 +201,10 @@
   // initialized.
   bool layer_tree_frame_sink_lost_;
 
+  // A number that kept incrementing in CompositeImmediately, which indicates a
+  // new impl frame.
+  uint64_t begin_frame_sequence_number_ = 1u;
+
   // This is the callback for the scheduled RequestNewLayerTreeFrameSink.
   base::CancelableOnceClosure layer_tree_frame_sink_creation_callback_;
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 8b4b7ac..00057d7 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=79
 MINOR=0
-BUILD=3909
+BUILD=3910
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 0414d06b..357d964 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -703,6 +703,7 @@
     "//chrome/android/webapk/libs/client:client_java",
     "//chrome/android/webapk/libs/common:common_java",
     "//chrome/android/webapk/test:junit_test_support",
+    "//chrome/browser/ui/android/widget:ui_widget_junit_tests",
     "//chrome/test/android:chrome_java_test_support",
     "//components/background_task_scheduler:background_task_scheduler_java",
     "//components/bookmarks/common/android:bookmarks_java",
@@ -1997,6 +1998,7 @@
     "//chrome/android/webapk/libs/runtime_library:runtime_library_javatests",
     "//chrome/android/webapk/shell_apk:shell_apk_javatests",
     "//chrome/browser/profiling_host:profiling_host_javatests",
+    "//chrome/browser/ui/android/widget:ui_widget_java_tests",
   ]
   if (enable_chrome_android_internal) {
     data_deps = [
@@ -2094,7 +2096,7 @@
   apk_name = "ChromeSmokeTest"
   android_manifest =
       "javatests/src/org/chromium/chrome/test/smoke/AndroidManifest.xml"
-  target_sdk_version = 28
+  target_sdk_version = android_sdk_version
   testonly = true
   java_files =
       [ "javatests/src/org/chromium/chrome/test/smoke/ChromeSmokeTest.java" ]
@@ -2131,7 +2133,7 @@
   apk_name = "ChromeBundleSmokeTest"
   android_manifest =
       "javatests/src/org/chromium/chrome/test/smoke/AndroidManifest_bundle.xml"
-  target_sdk_version = 28
+  target_sdk_version = android_sdk_version
   testonly = true
   java_files = [
     "javatests/src/org/chromium/chrome/test/smoke/ChromeBundleSmokeTest.java",
@@ -2146,16 +2148,34 @@
   ]
 }
 
+_bundle_smoke_test_extra_args = [
+  # Make extra args be passed through to the bundle under test (see below).
+  "--use-apk-under-test-flags-file",
+
+  # Chrome crashes at startup if strict mode is turned on.
+  "--strict-mode=off",
+
+  # These args are passed through to the bundle under test.
+  "--enable-test-dummy-module",
+  "--disable-fre",
+]
+
+instrumentation_test_runner("chrome_modern_public_bundle_smoke_test") {
+  apk_under_test = ":chrome_modern_public_bundle_apks"
+  android_test_apk = ":chrome_bundle_smoke_test_apk"
+  android_test_apk_name = "ChromeBundleSmokeTest"
+  never_incremental = true
+  modules = [ "test_dummy" ]
+  extra_args = _bundle_smoke_test_extra_args
+}
+
 instrumentation_test_runner("monochrome_public_bundle_smoke_test") {
   apk_under_test = "//chrome/android:monochrome_public_bundle_apks"
   android_test_apk = ":chrome_bundle_smoke_test_apk"
   android_test_apk_name = "ChromeBundleSmokeTest"
   never_incremental = true
   modules = [ "test_dummy" ]
-  command_line_args = [
-    "--enable-test-dummy-module",
-    "--no-fre",
-  ]
+  extra_args = _bundle_smoke_test_extra_args
 }
 
 if (defined(expected_static_initializer_count)) {
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 5be7ee1..ff03023 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1777,18 +1777,12 @@
   "java/src/org/chromium/chrome/browser/webshare/ShareServiceImpl.java",
   "java/src/org/chromium/chrome/browser/webshare/ShareServiceImplementationFactory.java",
   "java/src/org/chromium/chrome/browser/webshare/SharedFileCollator.java",
-  "java/src/org/chromium/chrome/browser/widget/AlertDialogEditText.java",
-  "java/src/org/chromium/chrome/browser/widget/AlwaysDismissedDialog.java",
-  "java/src/org/chromium/chrome/browser/widget/BoundedLinearLayout.java",
   "java/src/org/chromium/chrome/browser/widget/ChromeTextInputLayout.java",
   "java/src/org/chromium/chrome/browser/widget/ClipDrawableProgressBar.java",
   "java/src/org/chromium/chrome/browser/widget/ContextMenuDialog.java",
   "java/src/org/chromium/chrome/browser/widget/ControlContainer.java",
   "java/src/org/chromium/chrome/browser/widget/DateDividedAdapter.java",
-  "java/src/org/chromium/chrome/browser/widget/DualControlLayout.java",
-  "java/src/org/chromium/chrome/browser/widget/FadingEdgeScrollView.java",
   "java/src/org/chromium/chrome/browser/widget/FeatureHighlightProvider.java",
-  "java/src/org/chromium/chrome/browser/widget/LoadingView.java",
   "java/src/org/chromium/chrome/browser/widget/MaterialProgressBar.java",
   "java/src/org/chromium/chrome/browser/widget/NumberRollView.java",
   "java/src/org/chromium/chrome/browser/widget/OverviewListLayout.java",
@@ -1811,14 +1805,12 @@
   "java/src/org/chromium/chrome/browser/widget/TintedDrawable.java",
   "java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java",
   "java/src/org/chromium/chrome/browser/widget/ToolbarProgressBarAnimatingView.java",
-  "java/src/org/chromium/chrome/browser/widget/VerticallyFixedEditText.java",
   "java/src/org/chromium/chrome/browser/widget/ViewHighlighter.java",
   "java/src/org/chromium/chrome/browser/widget/ViewResourceFrameLayout.java",
   "java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelAdapter.java",
   "java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelListItem.java",
   "java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelListView.java",
   "java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java",
-  "java/src/org/chromium/chrome/browser/widget/accessibility/AccessibleTextView.java",
   "java/src/org/chromium/chrome/browser/widget/animation/AnimatorProperties.java",
   "java/src/org/chromium/chrome/browser/widget/animation/CancelAwareAnimatorListener.java",
   "java/src/org/chromium/chrome/browser/widget/animation/FocusAnimator.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index e9c13b8..006166e 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -526,7 +526,6 @@
   "javatests/src/org/chromium/chrome/browser/webauth/AuthenticatorTest.java",
   "javatests/src/org/chromium/chrome/browser/webshare/WebShareTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/ChromeTextInputLayoutRenderTest.java",
-  "javatests/src/org/chromium/chrome/browser/widget/DualControlLayoutTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/OverviewListLayoutTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/PromoDialogTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/RadioButtonLayoutTest.java",
diff --git a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_bottom_sheet_content.xml b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_bottom_sheet_content.xml
index 103c3c00..2a06b8ef 100644
--- a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_bottom_sheet_content.xml
+++ b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_bottom_sheet_content.xml
@@ -10,7 +10,7 @@
     android:layout_width="match_parent"
     android:paddingTop="12dp"
     android:orientation="vertical">
-    <org.chromium.chrome.browser.widget.FadingEdgeScrollView
+    <org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView
         android:id="@+id/scrollable_content"
         android:layout_width="match_parent"
         android:layout_height="0dp"
@@ -22,5 +22,5 @@
             android:orientation="vertical"
             android:clipChildren="false"
             android:clipToPadding="false" />
-    </org.chromium.chrome.browser.widget.FadingEdgeScrollView>
+    </org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView>
 </LinearLayout>
diff --git a/chrome/android/java/res/layout/add_site_dialog.xml b/chrome/android/java/res/layout/add_site_dialog.xml
index 3f11561..55302c4 100644
--- a/chrome/android/java/res/layout/add_site_dialog.xml
+++ b/chrome/android/java/res/layout/add_site_dialog.xml
@@ -11,7 +11,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/website_settings_add_site_site_url" />
-    <org.chromium.chrome.browser.widget.AlertDialogEditText
+    <org.chromium.chrome.browser.ui.widget.text.AlertDialogEditText
         android:id="@+id/site"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/chrome/android/java/res/layout/add_to_homescreen_dialog.xml b/chrome/android/java/res/layout/add_to_homescreen_dialog.xml
index 12259c2..8564f9d 100644
--- a/chrome/android/java/res/layout/add_to_homescreen_dialog.xml
+++ b/chrome/android/java/res/layout/add_to_homescreen_dialog.xml
@@ -27,7 +27,7 @@
         android:layout_marginTop="10dp" />
 
     <!-- An editable text field for the name of the home screen icon. -->
-    <org.chromium.chrome.browser.widget.AlertDialogEditText
+    <org.chromium.chrome.browser.ui.widget.text.AlertDialogEditText
         android:id="@+id/text"
         android:inputType="text"
         android:layout_width="match_parent"
diff --git a/chrome/android/java/res/layout/autofill_editor_base.xml b/chrome/android/java/res/layout/autofill_editor_base.xml
index e42d42f..d7e58210 100644
--- a/chrome/android/java/res/layout/autofill_editor_base.xml
+++ b/chrome/android/java/res/layout/autofill_editor_base.xml
@@ -12,7 +12,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent" >
 
-    <org.chromium.chrome.browser.widget.FadingEdgeScrollView
+    <org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView
         android:id="@+id/scroll_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
@@ -28,7 +28,7 @@
             android:paddingEnd="@dimen/pref_autofill_content_spacing"
             android:orientation="vertical" />
 
-    </org.chromium.chrome.browser.widget.FadingEdgeScrollView>
+    </org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView>
 
     <include layout="@layout/preferences_action_bar_shadow"/>
 
diff --git a/chrome/android/java/res/layout/autofill_editor_base_buttons.xml b/chrome/android/java/res/layout/autofill_editor_base_buttons.xml
index 48f8327..e461c04 100644
--- a/chrome/android/java/res/layout/autofill_editor_base_buttons.xml
+++ b/chrome/android/java/res/layout/autofill_editor_base_buttons.xml
@@ -10,7 +10,7 @@
     <Space style="@style/ButtonBarTopSpacerLight" />
 
     <!-- CANCEL and DONE buttons. -->
-    <org.chromium.chrome.browser.widget.DualControlLayout
+    <org.chromium.chrome.browser.ui.widget.DualControlLayout
         android:id="@+id/button_bar"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/chrome/android/java/res/layout/bluetooth_scanning_permission_dialog.xml b/chrome/android/java/res/layout/bluetooth_scanning_permission_dialog.xml
index 5481a09..8b56034 100644
--- a/chrome/android/java/res/layout/bluetooth_scanning_permission_dialog.xml
+++ b/chrome/android/java/res/layout/bluetooth_scanning_permission_dialog.xml
@@ -16,7 +16,7 @@
     <include layout="@layout/device_item_list" />
 
     <!-- Button row. -->
-    <org.chromium.chrome.browser.widget.DualControlLayout
+    <org.chromium.chrome.browser.ui.widget.DualControlLayout
         android:id="@+id/button_bar"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -40,6 +40,6 @@
             android:layout_gravity="end"
             style="@style/TextButton" />
 
-    </org.chromium.chrome.browser.widget.DualControlLayout>
+    </org.chromium.chrome.browser.ui.widget.DualControlLayout>
 
 </LinearLayout>
diff --git a/chrome/android/java/res/layout/custom_tabs_bottombar.xml b/chrome/android/java/res/layout/custom_tabs_bottombar.xml
index 3fc7bd3..a9933e08 100644
--- a/chrome/android/java/res/layout/custom_tabs_bottombar.xml
+++ b/chrome/android/java/res/layout/custom_tabs_bottombar.xml
@@ -2,7 +2,7 @@
 <!-- Copyright 2015 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. -->
-<org.chromium.chrome.browser.widget.BoundedLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<org.chromium.chrome.browser.ui.widget.BoundedLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -15,4 +15,4 @@
         android:layout_height="4dp"
         android:background="@drawable/infobar_shadow_top" />
 
-</org.chromium.chrome.browser.widget.BoundedLinearLayout>
\ No newline at end of file
+</org.chromium.chrome.browser.ui.widget.BoundedLinearLayout>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/explore_sites_loading_from_net_view.xml b/chrome/android/java/res/layout/explore_sites_loading_from_net_view.xml
index 74f202a..ef0582d4 100644
--- a/chrome/android/java/res/layout/explore_sites_loading_from_net_view.xml
+++ b/chrome/android/java/res/layout/explore_sites_loading_from_net_view.xml
@@ -10,7 +10,7 @@
     android:layout_height="match_parent"
     android:gravity="center"
     android:orientation="vertical" >
-    <org.chromium.chrome.browser.widget.LoadingView
+    <org.chromium.chrome.browser.ui.widget.LoadingView
         android:id="@+id/loading"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/chrome/android/java/res/layout/http_auth_dialog.xml b/chrome/android/java/res/layout/http_auth_dialog.xml
index 1e4a16b..1136199 100644
--- a/chrome/android/java/res/layout/http_auth_dialog.xml
+++ b/chrome/android/java/res/layout/http_auth_dialog.xml
@@ -21,7 +21,7 @@
           android:id="@+id/username_label"
           android:layout_width="match_parent"
           android:layout_height="wrap_content" >
-          <org.chromium.chrome.browser.widget.AlertDialogEditText
+          <org.chromium.chrome.browser.ui.widget.text.AlertDialogEditText
               android:id="@+id/username"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
@@ -35,7 +35,7 @@
           android:id="@+id/password_label"
           android:layout_width="match_parent"
           android:layout_height="wrap_content" >
-          <org.chromium.chrome.browser.widget.AlertDialogEditText
+          <org.chromium.chrome.browser.ui.widget.text.AlertDialogEditText
               android:id="@+id/password"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
diff --git a/chrome/android/java/res/layout/infobar_control_icon_with_description.xml b/chrome/android/java/res/layout/infobar_control_icon_with_description.xml
index f32fc912..37d67464 100644
--- a/chrome/android/java/res/layout/infobar_control_icon_with_description.xml
+++ b/chrome/android/java/res/layout/infobar_control_icon_with_description.xml
@@ -15,11 +15,11 @@
         android:id="@+id/control_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/infobar_control_margin_between_items"
+        android:layout_marginEnd="@dimen/dual_control_margin_between_items"
         android:scaleType="centerInside"
         tools:ignore="ContentDescription" />
 
-    <org.chromium.chrome.browser.widget.DualControlLayout
+    <org.chromium.chrome.browser.ui.widget.DualControlLayout
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_weight="1" >
@@ -36,6 +36,6 @@
             android:layout_height="wrap_content"
             android:textAppearance="@style/TextAppearance.BlackHint1" />
 
-    </org.chromium.chrome.browser.widget.DualControlLayout>
+    </org.chromium.chrome.browser.ui.widget.DualControlLayout>
 
 </LinearLayout>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/infobar_control_spinner_view.xml b/chrome/android/java/res/layout/infobar_control_spinner_view.xml
index f6c834c9c..ea5056c 100644
--- a/chrome/android/java/res/layout/infobar_control_spinner_view.xml
+++ b/chrome/android/java/res/layout/infobar_control_spinner_view.xml
@@ -5,7 +5,7 @@
      found in the LICENSE file.
 -->
 
-<org.chromium.chrome.browser.widget.DualControlLayout
+<org.chromium.chrome.browser.ui.widget.DualControlLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content" >
@@ -22,4 +22,4 @@
         android:layout_height="wrap_content"
         android:textAppearance="@style/TextAppearance.BlackTitle1" />
 
-</org.chromium.chrome.browser.widget.DualControlLayout>
\ No newline at end of file
+</org.chromium.chrome.browser.ui.widget.DualControlLayout>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/infobar_control_toggle.xml b/chrome/android/java/res/layout/infobar_control_toggle.xml
index 27cd257..fdf2fde 100644
--- a/chrome/android/java/res/layout/infobar_control_toggle.xml
+++ b/chrome/android/java/res/layout/infobar_control_toggle.xml
@@ -15,7 +15,7 @@
         android:id="@+id/control_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/infobar_control_margin_between_items"
+        android:layout_marginEnd="@dimen/dual_control_margin_between_items"
         android:scaleType="centerInside"
         tools:ignore="ContentDescription" />
 
@@ -24,7 +24,7 @@
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_weight="1"
-        android:layout_marginEnd="@dimen/infobar_control_margin_between_items"
+        android:layout_marginEnd="@dimen/dual_control_margin_between_items"
         android:gravity="center_vertical"
         android:textAppearance="@style/TextAppearance.BlackTitle1" />
 
diff --git a/chrome/android/java/res/layout/js_modal_dialog.xml b/chrome/android/java/res/layout/js_modal_dialog.xml
index fed6b532..8f412ab 100644
--- a/chrome/android/java/res/layout/js_modal_dialog.xml
+++ b/chrome/android/java/res/layout/js_modal_dialog.xml
@@ -13,7 +13,7 @@
     style="@style/AlertDialogContent"
     android:orientation="vertical">
 
-    <org.chromium.chrome.browser.widget.AlertDialogEditText
+    <org.chromium.chrome.browser.ui.widget.text.AlertDialogEditText
         android:id="@+id/js_modal_dialog_prompt"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/chrome/android/java/res/layout/lightweight_fre_tos.xml b/chrome/android/java/res/layout/lightweight_fre_tos.xml
index 82ff098..33d8a1b 100644
--- a/chrome/android/java/res/layout/lightweight_fre_tos.xml
+++ b/chrome/android/java/res/layout/lightweight_fre_tos.xml
@@ -34,7 +34,7 @@
         android:paddingStart="24dp"
         android:textAppearance="@style/TextAppearance.BlackBodyDefault" />
 
-    <org.chromium.chrome.browser.widget.DualControlLayout
+    <org.chromium.chrome.browser.ui.widget.DualControlLayout
         android:id="@+id/lightweight_fre_buttons"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/chrome/android/java/res/layout/modal_dialog_view.xml b/chrome/android/java/res/layout/modal_dialog_view.xml
index c75cc2b3..d614de45 100644
--- a/chrome/android/java/res/layout/modal_dialog_view.xml
+++ b/chrome/android/java/res/layout/modal_dialog_view.xml
@@ -15,7 +15,7 @@
     <include layout="@layout/modal_dialog_title"
         android:id="@+id/title_container" />
 
-    <org.chromium.chrome.browser.widget.FadingEdgeScrollView
+    <org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView
         android:id="@+id/modal_dialog_scroll_view"
         android:layout_width="match_parent"
         android:layout_height="0dp"
@@ -39,7 +39,7 @@
 
         </LinearLayout>
 
-    </org.chromium.chrome.browser.widget.FadingEdgeScrollView>
+    </org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView>
 
     <FrameLayout
         android:id="@+id/custom"
@@ -48,7 +48,7 @@
         android:layout_weight="1"
         android:visibility="gone" />
 
-    <org.chromium.chrome.browser.widget.DualControlLayout
+    <org.chromium.chrome.browser.ui.widget.DualControlLayout
         android:id="@+id/button_bar"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -71,6 +71,6 @@
             android:layout_height="wrap_content"
             style="?attr/buttonBarNegativeButtonStyle" />
 
-    </org.chromium.chrome.browser.widget.DualControlLayout>
+    </org.chromium.chrome.browser.ui.widget.DualControlLayout>
 
 </org.chromium.chrome.browser.modaldialog.ModalDialogView>
diff --git a/chrome/android/java/res/layout/payment_request.xml b/chrome/android/java/res/layout/payment_request.xml
index 8a9061af..7e50f62 100644
--- a/chrome/android/java/res/layout/payment_request.xml
+++ b/chrome/android/java/res/layout/payment_request.xml
@@ -6,7 +6,7 @@
 <!-- PaymentRequestUI dialog
      Sits at the bottom of the screen like a Bottom Sheet.
 -->
-<org.chromium.chrome.browser.widget.BoundedLinearLayout
+<org.chromium.chrome.browser.ui.widget.BoundedLinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/payment_request"
@@ -19,7 +19,7 @@
     <include layout="@layout/payment_request_header" />
     <include layout="@layout/payment_request_spinny" />
 
-    <org.chromium.chrome.browser.widget.FadingEdgeScrollView
+    <org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView
         android:id="@+id/option_container"
         android:layout_height="0dp"
         android:layout_width="match_parent"
@@ -41,8 +41,8 @@
                 android:textAppearance="@style/TextAppearance.PaymentsUiSectionWarningText" />
         </LinearLayout>
 
-    </org.chromium.chrome.browser.widget.FadingEdgeScrollView>
+    </org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView>
 
      <include layout="@layout/payment_request_bottom_bar" />
 
-</org.chromium.chrome.browser.widget.BoundedLinearLayout>
+</org.chromium.chrome.browser.ui.widget.BoundedLinearLayout>
diff --git a/chrome/android/java/res/layout/payment_request_editor.xml b/chrome/android/java/res/layout/payment_request_editor.xml
index 809ee3e..73b4a951 100644
--- a/chrome/android/java/res/layout/payment_request_editor.xml
+++ b/chrome/android/java/res/layout/payment_request_editor.xml
@@ -21,7 +21,7 @@
     <include layout="@layout/preferences_action_bar_shadow" />
 
     <!-- All the page content in scrollable form. -->
-    <org.chromium.chrome.browser.widget.FadingEdgeScrollView
+    <org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView
         android:id="@+id/scroll_view"
         android:layout_height="0dp"
         android:layout_width="match_parent"
@@ -38,6 +38,6 @@
             android:paddingEnd="@dimen/pref_autofill_content_spacing"
             android:orientation="vertical" />
 
-    </org.chromium.chrome.browser.widget.FadingEdgeScrollView>
+    </org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView>
 
 </RelativeLayout>
diff --git a/chrome/android/java/res/layout/promo_dialog_layout.xml b/chrome/android/java/res/layout/promo_dialog_layout.xml
index 4695102..4be9b76 100644
--- a/chrome/android/java/res/layout/promo_dialog_layout.xml
+++ b/chrome/android/java/res/layout/promo_dialog_layout.xml
@@ -24,7 +24,7 @@
             app:maxWidthLandscape="@dimen/dialog_max_width"
             app:maxWidthPortrait="@dimen/dialog_max_width" >
 
-        <org.chromium.chrome.browser.widget.FadingEdgeScrollView
+        <org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView
                 android:id="@+id/promo_container"
                 android:layout_width="match_parent"
                 android:layout_height="0dp"
@@ -51,7 +51,7 @@
                         android:scaleType="fitCenter"
                         tools:ignore="ContentDescription" />
 
-                <org.chromium.chrome.browser.widget.BoundedLinearLayout
+                <org.chromium.chrome.browser.ui.widget.BoundedLinearLayout
                         android:id="@+id/scrollable_promo_content"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
@@ -72,10 +72,10 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         style="@style/PromoDialogNormalText" />
-                </org.chromium.chrome.browser.widget.BoundedLinearLayout>
+                </org.chromium.chrome.browser.ui.widget.BoundedLinearLayout>
             </LinearLayout>
 
-        </org.chromium.chrome.browser.widget.FadingEdgeScrollView>
+        </org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView>
 
         <ViewStub
                 android:id="@+id/footer_stub"
@@ -85,7 +85,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content" />
 
-        <org.chromium.chrome.browser.widget.DualControlLayout
+        <org.chromium.chrome.browser.ui.widget.DualControlLayout
                 android:id="@+id/button_bar"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
diff --git a/chrome/android/java/res/layout/selectable_list_layout.xml b/chrome/android/java/res/layout/selectable_list_layout.xml
index 873359a5..4404da24 100644
--- a/chrome/android/java/res/layout/selectable_list_layout.xml
+++ b/chrome/android/java/res/layout/selectable_list_layout.xml
@@ -59,7 +59,7 @@
 
         </FrameLayout>
 
-        <org.chromium.chrome.browser.widget.LoadingView
+        <org.chromium.chrome.browser.ui.widget.LoadingView
             android:id="@+id/loading_view"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
diff --git a/chrome/android/java/res/layout/sync_custom_passphrase.xml b/chrome/android/java/res/layout/sync_custom_passphrase.xml
index 3985e205..c88dfd6 100644
--- a/chrome/android/java/res/layout/sync_custom_passphrase.xml
+++ b/chrome/android/java/res/layout/sync_custom_passphrase.xml
@@ -11,7 +11,7 @@
     <LinearLayout
         android:orientation="vertical"
         style="@style/AlertDialogContent">
-        <org.chromium.chrome.browser.widget.AlertDialogEditText
+        <org.chromium.chrome.browser.ui.widget.text.AlertDialogEditText
             android:id="@+id/passphrase"
             android:hint="@string/sync_enter_custom_passphrase_hint"
             android:layout_width="match_parent"
@@ -19,7 +19,7 @@
             android:inputType="textPassword"
             android:singleLine="true"
             android:imeOptions="actionNext" />
-        <org.chromium.chrome.browser.widget.AlertDialogEditText
+        <org.chromium.chrome.browser.ui.widget.text.AlertDialogEditText
             android:id="@+id/confirm_passphrase"
             android:hint="@string/sync_enter_custom_passphrase_hint_confirm"
             android:layout_width="match_parent"
diff --git a/chrome/android/java/res/layout/sync_enter_passphrase.xml b/chrome/android/java/res/layout/sync_enter_passphrase.xml
index 0387499..060db77 100644
--- a/chrome/android/java/res/layout/sync_enter_passphrase.xml
+++ b/chrome/android/java/res/layout/sync_enter_passphrase.xml
@@ -16,7 +16,7 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginBottom="25dp" />
-        <org.chromium.chrome.browser.widget.AlertDialogEditText
+        <org.chromium.chrome.browser.ui.widget.text.AlertDialogEditText
             android:id="@+id/passphrase"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/chrome/android/java/res/layout/updating_gms_progress_view.xml b/chrome/android/java/res/layout/updating_gms_progress_view.xml
index dc248d4..8882df4 100644
--- a/chrome/android/java/res/layout/updating_gms_progress_view.xml
+++ b/chrome/android/java/res/layout/updating_gms_progress_view.xml
@@ -3,7 +3,7 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<org.chromium.chrome.browser.widget.BoundedLinearLayout
+<org.chromium.chrome.browser.ui.widget.BoundedLinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:gravity="center"
@@ -18,13 +18,13 @@
         android:layout_height="32dp"
         android:layout_gravity="center_vertical" />
 
-    <TextView
+    <org.chromium.ui.widget.TextViewWithLeading
         android:id="@+id/message"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
         android:layout_marginStart="24dp"
         android:text="@string/signin_gms_updating"
-        android:lineSpacingMultiplier="1.4"
-        android:textSize="14sp" />
-</org.chromium.chrome.browser.widget.BoundedLinearLayout>
+        android:textAppearance="@style/TextAppearance.BlackBodyDefault"
+        app:leading="@dimen/text_size_medium_leading" />
+</org.chromium.chrome.browser.ui.widget.BoundedLinearLayout>
diff --git a/chrome/android/java/res/values/attrs.xml b/chrome/android/java/res/values/attrs.xml
index ac7eec94..b02fa410 100644
--- a/chrome/android/java/res/values/attrs.xml
+++ b/chrome/android/java/res/values/attrs.xml
@@ -48,13 +48,6 @@
         <attr name="maxChildHeight" format="dimension" />
     </declare-styleable>
 
-    <declare-styleable name="BoundedView">
-        <attr name="maxWidth" format="dimension" />
-        <attr name="maxWidthLandscape" format="dimension" />
-        <attr name="maxWidthPortrait" format="dimension" />
-        <attr name="maxHeight" format="dimension" />
-    </declare-styleable>
-
     <declare-styleable name="MaterialProgressBar">
         <attr name="colorBackground" format="reference|color" />
         <attr name="colorProgress" format="reference|color" />
@@ -86,9 +79,4 @@
         <attr name="hint" format="reference|string" />
         <attr name="errorTextAppearance" format="reference" />
     </declare-styleable>
-
-    <declare-styleable name="DualControlLayout">
-        <attr name="dualControlLayoutVerticalPadding" format="dimension"/>
-        <attr name="dualControlLayoutHorizontalPadding" format="dimension"/>
-    </declare-styleable>
 </resources>
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index a0a25eaf..afdd6f9 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -24,7 +24,6 @@
     <color name="modal_dialog_scrim_color">@color/black_alpha_65</color>
 
     <!-- Modern color palette -->
-    <color name="black_alpha_11">#1D000000</color>
     <color name="black_alpha_12">#1F000000</color>
     <color name="black_alpha_20">#33000000</color>
     <color name="black_alpha_30">#4D000000</color>
@@ -127,7 +126,6 @@
     <color name="toolbar_background_primary_incognito">@color/default_bg_color_dark_elev_3</color>
     <color name="toolbar_text_box_background">@color/modern_grey_100</color>
     <color name="toolbar_text_box_background_incognito">@color/black_alpha_38</color>
-    <color name="toolbar_shadow_color">@color/black_alpha_11</color>
 
     <!-- LocationBar colors -->
     <color name="locationbar_dark_hint_text">@color/search_box_hint</color>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index e880180..f12fb85 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -92,7 +92,6 @@
     <dimen name="infobar_margin_above_button_row">32dp</dimen>
 
     <!-- Margin between items in the same control group. -->
-    <dimen name="infobar_control_margin_between_items">8dp</dimen>
     <dimen name="infobar_control_margin_between_rows">8dp</dimen>
     <dimen name="infobar_control_margin_between_columns">32dp</dimen>
 
@@ -548,7 +547,6 @@
          https://www.google.com/design/spec/components/dialogs.html#dialogs-simple-dialogs -->
     <dimen name="dialog_width_unit">56dp</dimen>  <!-- MD dialog widths are multiples of this. -->
     <dimen name="dialog_header_margin">14dp</dimen>
-    <dimen name="separator_height">1dp</dimen>
 
     <!-- Modern List Item dimensions -->
     <dimen name="list_item_min_height">64dp</dimen>
diff --git a/chrome/android/java/res/values/ids.xml b/chrome/android/java/res/values/ids.xml
index c4082b1..bfbcdbdb 100644
--- a/chrome/android/java/res/values/ids.xml
+++ b/chrome/android/java/res/values/ids.xml
@@ -22,8 +22,6 @@
     <item type="id" name="close_tab" />
 
     <!-- InfoBar constants -->
-    <item type="id" name="button_primary" />
-    <item type="id" name="button_secondary" />
     <item type="id" name="infobar_icon" />
     <item type="id" name="infobar_close_button" />
     <item type="id" name="infobar_extra_check" />
diff --git a/chrome/android/java/res_download/layout/download_location_dialog.xml b/chrome/android/java/res_download/layout/download_location_dialog.xml
index 08db728d..efd2769 100644
--- a/chrome/android/java/res_download/layout/download_location_dialog.xml
+++ b/chrome/android/java/res_download/layout/download_location_dialog.xml
@@ -35,7 +35,7 @@
                 app:tint="@color/default_icon_color"
                 style="@style/ListItemStartIcon" />
 
-            <org.chromium.chrome.browser.widget.AlertDialogEditText
+            <org.chromium.chrome.browser.ui.widget.text.AlertDialogEditText
                 android:id="@+id/file_name"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
diff --git a/chrome/android/java/res_download/layout/download_rename_custom_dialog.xml b/chrome/android/java/res_download/layout/download_rename_custom_dialog.xml
index bed7e42..c6fdcd6 100644
--- a/chrome/android/java/res_download/layout/download_rename_custom_dialog.xml
+++ b/chrome/android/java/res_download/layout/download_rename_custom_dialog.xml
@@ -34,7 +34,7 @@
                 app:tint="@color/default_icon_color"
                 style="@style/ListItemStartIcon" />
 
-            <org.chromium.chrome.browser.widget.AlertDialogEditText
+            <org.chromium.chrome.browser.ui.widget.text.AlertDialogEditText
                 android:id="@+id/file_name"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
diff --git a/chrome/android/java/res_download/layout/downloads_empty_view.xml b/chrome/android/java/res_download/layout/downloads_empty_view.xml
index 58f8214..f4eefa1 100644
--- a/chrome/android/java/res_download/layout/downloads_empty_view.xml
+++ b/chrome/android/java/res_download/layout/downloads_empty_view.xml
@@ -28,7 +28,7 @@
 
     </FrameLayout>
 
-    <org.chromium.chrome.browser.widget.LoadingView
+    <org.chromium.chrome.browser.ui.widget.LoadingView
         android:id="@+id/loading"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadLocationCustomView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadLocationCustomView.java
index f25930b..54f487a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadLocationCustomView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadLocationCustomView.java
@@ -19,7 +19,7 @@
 
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.preferences.download.DownloadDirectoryAdapter;
-import org.chromium.chrome.browser.widget.AlertDialogEditText;
+import org.chromium.chrome.browser.ui.widget.text.AlertDialogEditText;
 import org.chromium.chrome.download.R;
 
 import java.io.File;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyView.java
index c6a0f56..ff9f923 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyView.java
@@ -12,7 +12,7 @@
 import android.widget.TextView;
 
 import org.chromium.chrome.browser.download.home.empty.EmptyProperties.State;
-import org.chromium.chrome.browser.widget.LoadingView;
+import org.chromium.chrome.browser.ui.widget.LoadingView;
 import org.chromium.chrome.download.R;
 
 /** A view that represents the visuals required for the empty state of the download home list. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/rename/RenameDialogCustomView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/rename/RenameDialogCustomView.java
index 7c1c946..4866c2fd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/rename/RenameDialogCustomView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/rename/RenameDialogCustomView.java
@@ -17,7 +17,7 @@
 import android.widget.TextView;
 
 import org.chromium.base.Callback;
-import org.chromium.chrome.browser.widget.AlertDialogEditText;
+import org.chromium.chrome.browser.ui.widget.text.AlertDialogEditText;
 import org.chromium.chrome.download.R;
 import org.chromium.components.offline_items_collection.RenameResult;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/CategoryCardAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/CategoryCardAdapter.java
index da01987..af12810 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/CategoryCardAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/CategoryCardAdapter.java
@@ -14,7 +14,7 @@
 import org.chromium.chrome.browser.native_page.ContextMenuManager;
 import org.chromium.chrome.browser.native_page.NativePageNavigationDelegate;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.widget.LoadingView;
+import org.chromium.chrome.browser.ui.widget.LoadingView;
 import org.chromium.chrome.browser.widget.RoundedIconGenerator;
 import org.chromium.ui.modelutil.ForwardingListObservable;
 import org.chromium.ui.modelutil.ListObservable.ListObserver;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarControlLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarControlLayout.java
index 14e2101a..8984e55 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarControlLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarControlLayout.java
@@ -24,7 +24,7 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.widget.DualControlLayout;
+import org.chromium.chrome.browser.ui.widget.DualControlLayout;
 import org.chromium.chrome.browser.widget.RadioButtonLayout;
 
 import java.util.List;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarLayout.java
index 0b13c10e..38bd57de 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarLayout.java
@@ -27,7 +27,7 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.widget.DualControlLayout;
+import org.chromium.chrome.browser.ui.widget.DualControlLayout;
 import org.chromium.ui.UiUtils;
 import org.chromium.ui.text.NoUnderlineClickableSpan;
 import org.chromium.ui.widget.ButtonCompat;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InstallableAmbientBadgeInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InstallableAmbientBadgeInfoBar.java
index 101e0d22..43f833a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InstallableAmbientBadgeInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InstallableAmbientBadgeInfoBar.java
@@ -18,7 +18,7 @@
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ResourceId;
-import org.chromium.chrome.browser.widget.accessibility.AccessibleTextView;
+import org.chromium.chrome.browser.ui.widget.text.AccessibleTextView;
 
 /**
  * An ambient infobar to tell the user that the current site they are visiting is a PWA.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InstantAppsInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InstantAppsInfoBar.java
index d9a55df..155bdf9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InstantAppsInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InstantAppsInfoBar.java
@@ -10,7 +10,7 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.instantapps.InstantAppsBannerData;
-import org.chromium.chrome.browser.widget.DualControlLayout;
+import org.chromium.chrome.browser.ui.widget.DualControlLayout;
 import org.chromium.components.url_formatter.UrlFormatter;
 
 /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ReaderModeInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ReaderModeInfoBar.java
index e5036a28..76c282f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ReaderModeInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ReaderModeInfoBar.java
@@ -20,7 +20,7 @@
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
 import org.chromium.chrome.browser.dom_distiller.ReaderModeManager;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.widget.accessibility.AccessibleTextView;
+import org.chromium.chrome.browser.ui.widget.text.AccessibleTextView;
 
 /**
  * This is the InfoBar implementation of the Reader Mode UI. This is used in place of the
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/ModalDialogView.java b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/ModalDialogView.java
index c4c6b65..baced4e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/ModalDialogView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/ModalDialogView.java
@@ -19,8 +19,8 @@
 import org.chromium.base.Callback;
 import org.chromium.base.Log;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.widget.BoundedLinearLayout;
-import org.chromium.chrome.browser.widget.FadingEdgeScrollView;
+import org.chromium.chrome.browser.ui.widget.BoundedLinearLayout;
+import org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView;
 import org.chromium.ui.UiUtils;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/LogoView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/LogoView.java
index 1a8be49e..6c22751e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/LogoView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/LogoView.java
@@ -30,7 +30,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ntp.LogoBridge.Logo;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
-import org.chromium.chrome.browser.widget.LoadingView;
+import org.chromium.chrome.browser.ui.widget.LoadingView;
 
 import java.lang.ref.WeakReference;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java
index 02d5b9f..474693f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java
@@ -22,7 +22,7 @@
 import org.chromium.base.StrictModeContext;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.widget.VerticallyFixedEditText;
+import org.chromium.chrome.browser.ui.widget.text.VerticallyFixedEditText;
 
 /**
  * An {@link EditText} that shows autocomplete text at the end.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/DimmingDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/DimmingDialog.java
index b8edacbdd..f9e2fdc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/DimmingDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/DimmingDialog.java
@@ -28,8 +28,8 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ui.widget.AlwaysDismissedDialog;
 import org.chromium.chrome.browser.util.ColorUtils;
-import org.chromium.chrome.browser.widget.AlwaysDismissedDialog;
 import org.chromium.chrome.browser.widget.animation.AnimatorProperties;
 
 /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
index 9add67f..ef40660 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
@@ -36,7 +36,7 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.widget.DualControlLayout;
+import org.chromium.chrome.browser.ui.widget.DualControlLayout;
 import org.chromium.chrome.browser.widget.TintedDrawable;
 import org.chromium.chrome.browser.widget.prefeditor.EditableOption;
 import org.chromium.ui.HorizontalListDividerDrawable;
@@ -1517,7 +1517,7 @@
             setBackground(HorizontalListDividerDrawable.create(getContext()));
             LinearLayout.LayoutParams params =
                     new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
-                            resources.getDimensionPixelSize(R.dimen.separator_height));
+                            resources.getDimensionPixelSize(R.dimen.divider_height));
 
             int margin =
                     resources.getDimensionPixelSize(R.dimen.editor_dialog_section_large_spacing);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
index 62d299e..e34f12d6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
@@ -43,7 +43,7 @@
 import org.chromium.chrome.browser.payments.ui.PaymentRequestSection.LineItemBreakdownSection;
 import org.chromium.chrome.browser.payments.ui.PaymentRequestSection.OptionSection;
 import org.chromium.chrome.browser.payments.ui.PaymentRequestSection.SectionSeparator;
-import org.chromium.chrome.browser.widget.FadingEdgeScrollView;
+import org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView;
 import org.chromium.chrome.browser.widget.animation.FocusAnimator;
 import org.chromium.chrome.browser.widget.prefeditor.EditableOption;
 import org.chromium.chrome.browser.widget.prefeditor.EditorDialog;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUiErrorView.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUiErrorView.java
index 18f0547..e4023dd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUiErrorView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUiErrorView.java
@@ -12,7 +12,7 @@
 import android.view.ViewGroup;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.widget.BoundedLinearLayout;
+import org.chromium.chrome.browser.ui.widget.BoundedLinearLayout;
 
 /**
  * Displays the status of a payment request to the user.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillEditorBase.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillEditorBase.java
index 9ac9392..fd21b452 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillEditorBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillEditorBase.java
@@ -28,7 +28,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.preferences.MainPreferences;
 import org.chromium.chrome.browser.preferences.PreferenceUtils;
-import org.chromium.chrome.browser.widget.FadingEdgeScrollView;
+import org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView;
 import org.chromium.chrome.browser.widget.prefeditor.EditorDialog;
 
 /** Base class for Autofill editors (e.g. credit cards and profiles). */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ContextMenuDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ContextMenuDialog.java
index 47b2ec8..2e97766 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ContextMenuDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ContextMenuDialog.java
@@ -19,6 +19,8 @@
 import android.view.animation.Animation.AnimationListener;
 import android.view.animation.ScaleAnimation;
 
+import org.chromium.chrome.browser.ui.widget.AlwaysDismissedDialog;
+
 /**
  * ContextMenuDialog is a subclass of AlwaysDismissedDialog that ensures that the proper scale
  * animation is played upon calling {@link #show()} and {@link #dismiss()}.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialog.java
index d2c4413..43fa1bdd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialog.java
@@ -18,6 +18,7 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ui.widget.AlwaysDismissedDialog;
 
 /**
  * Generic builder for promo dialogs.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialogLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialogLayout.java
index f4952ed..e85a8ab0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialogLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialogLayout.java
@@ -16,6 +16,8 @@
 import android.widget.TextView;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ui.widget.BoundedLinearLayout;
+import org.chromium.chrome.browser.ui.widget.DualControlLayout;
 import org.chromium.chrome.browser.widget.PromoDialog.DialogParams;
 
 /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
index a6d63840..16825a4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
@@ -48,7 +48,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
 import org.chromium.chrome.browser.tabmodel.TabSelectionType;
-import org.chromium.chrome.browser.widget.VerticallyFixedEditText;
+import org.chromium.chrome.browser.ui.widget.text.VerticallyFixedEditText;
 import org.chromium.ui.base.WindowAndroid;
 
 import java.lang.annotation.Retention;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/prefeditor/EditorDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/prefeditor/EditorDialog.java
index 69ae294f..1d50a8d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/prefeditor/EditorDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/prefeditor/EditorDialog.java
@@ -47,8 +47,8 @@
 import org.chromium.chrome.browser.preferences.PreferenceUtils;
 import org.chromium.chrome.browser.preferences.autofill.CreditCardNumberFormattingTextWatcher;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.widget.AlwaysDismissedDialog;
-import org.chromium.chrome.browser.widget.FadingEdgeScrollView;
+import org.chromium.chrome.browser.ui.widget.AlwaysDismissedDialog;
+import org.chromium.chrome.browser.ui.widget.FadingEdgeScrollView;
 import org.chromium.chrome.browser.widget.TintedDrawable;
 import org.chromium.ui.KeyboardVisibilityDelegate;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListLayout.java
index 3a81446..8e7225f4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListLayout.java
@@ -29,7 +29,7 @@
 import org.chromium.chrome.browser.gesturenav.HistoryNavigationLayout;
 import org.chromium.chrome.browser.ui.widget.FadingShadow;
 import org.chromium.chrome.browser.ui.widget.FadingShadowView;
-import org.chromium.chrome.browser.widget.LoadingView;
+import org.chromium.chrome.browser.ui.widget.LoadingView;
 import org.chromium.chrome.browser.widget.displaystyle.DisplayStyleObserver;
 import org.chromium.chrome.browser.widget.displaystyle.HorizontalDisplayStyle;
 import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 3445194..3f3e9618 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1709,10 +1709,10 @@
     Removable device detected
   </message>
   <message name="IDS_REMOVABLE_DEVICE_NAVIGATION_MESSAGE" desc="Text of notification message to navigate users to the Files app. If user clicks a button in the notification, the Files app opens.">
-    Explore the device's content in the Files app.
+    Explore the device’s content in the Files app.
   </message>
   <message name="IDS_REMOVABLE_DEVICE_ALLOW_PLAY_STORE_ACCESS_MESSAGE" desc="Text of notification message to navigate users to the ARC settings page. If user clicks a button in the notification, the page opens.">
-    To allow full file system access for apps from Google Play, go to Settings.
+    For device preferences, go to Settings.
   </message>
   <message name="IDS_REMOVABLE_DEVICE_PLAY_STORE_APPS_HAVE_ACCESS_MESSAGE" desc="Text of notification message to navigate users to the ARC settings page. If user clicks a button in the notification, the page opens.">
     Play Store applications have access to this device.
diff --git a/chrome/app/global_media_controls_strings.grdp b/chrome/app/global_media_controls_strings.grdp
index 10cdb83..1cda455 100644
--- a/chrome/app/global_media_controls_strings.grdp
+++ b/chrome/app/global_media_controls_strings.grdp
@@ -4,4 +4,7 @@
   <message name="IDS_GLOBAL_MEDIA_CONTROLS_ICON_TOOLTIP_TEXT" desc="Tooltip for the Global Media Controls icon, which appears in the toolbar. The tooltip appears on mouseover of the icon.">
    Control your music, videos, and more
   </message>
+  <message name="IDS_GLOBAL_MEDIA_CONTROLS_DISMISS_ICON_TOOLTIP_TEXT" desc="Tooltip for the dismiss button within the Global Media Controls dialog. The tooltip appears on mouseover of the icon.">
+   Dismiss
+  </message>
 </grit-part>
diff --git a/chrome/app/global_media_controls_strings_grdp/IDS_GLOBAL_MEDIA_CONTROLS_DISMISS_ICON_TOOLTIP_TEXT.png.sha1 b/chrome/app/global_media_controls_strings_grdp/IDS_GLOBAL_MEDIA_CONTROLS_DISMISS_ICON_TOOLTIP_TEXT.png.sha1
new file mode 100644
index 0000000..55967858
--- /dev/null
+++ b/chrome/app/global_media_controls_strings_grdp/IDS_GLOBAL_MEDIA_CONTROLS_DISMISS_ICON_TOOLTIP_TEXT.png.sha1
@@ -0,0 +1 @@
+5ac1f13bc47454fdf113c1b53b8e03f9bd161525
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 8632f4f9..2cfa1c2 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1413,7 +1413,7 @@
     {"enable-webrtc-hide-local-ips-with-mdns",
      flag_descriptions::kWebrtcHideLocalIpsWithMdnsName,
      flag_descriptions::kWebrtcHideLocalIpsWithMdnsDecription, kOsDesktop,
-     FEATURE_VALUE_TYPE(features::kWebRtcHideLocalIpsWithMdns)},
+     FEATURE_VALUE_TYPE(blink::features::kWebRtcHideLocalIpsWithMdns)},
 #if defined(OS_ANDROID)
     {"clear-old-browsing-data", flag_descriptions::kClearOldBrowsingDataName,
      flag_descriptions::kClearOldBrowsingDataDescription, kOsAndroid,
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index 0f20ef9..747675f 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -516,7 +516,7 @@
                                    const JavaParamRef<jobject>& obj) {
   content::RenderFrameHost* render_frame_host =
       web_contents()->GetFocusedFrame();
-  chrome::mojom::ChromeRenderFrameAssociatedPtr renderer;
+  mojo::AssociatedRemote<chrome::mojom::ChromeRenderFrame> renderer;
   render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(&renderer);
   renderer->RequestReloadImageForContextNode();
 }
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
index 529f6eac..b9500a3 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -123,7 +123,7 @@
   DCHECK(shortcut_info_.url.is_valid());
 
   // Send a message to the renderer to retrieve information about the page.
-  chrome::mojom::ChromeRenderFrameAssociatedPtr chrome_render_frame;
+  mojo::AssociatedRemote<chrome::mojom::ChromeRenderFrame> chrome_render_frame;
   web_contents->GetMainFrame()->GetRemoteAssociatedInterfaces()->GetInterface(
       &chrome_render_frame);
   // Bind the InterfacePtr into the callback so that it's kept alive
@@ -137,7 +137,8 @@
 AddToHomescreenDataFetcher::~AddToHomescreenDataFetcher() {}
 
 void AddToHomescreenDataFetcher::OnDidGetWebApplicationInfo(
-    chrome::mojom::ChromeRenderFrameAssociatedPtr chrome_render_frame,
+    mojo::AssociatedRemote<chrome::mojom::ChromeRenderFrame>
+        chrome_render_frame,
     const WebApplicationInfo& received_web_app_info) {
   if (!web_contents())
     return;
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
index 558b83ef..60aee6b 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
@@ -16,6 +16,7 @@
 #include "chrome/browser/android/shortcut_info.h"
 #include "chrome/common/chrome_render_frame.mojom.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
 namespace favicon_base {
@@ -59,7 +60,8 @@
 
   // IPC message received when the initialization is finished.
   void OnDidGetWebApplicationInfo(
-      chrome::mojom::ChromeRenderFrameAssociatedPtr chrome_render_frame,
+      mojo::AssociatedRemote<chrome::mojom::ChromeRenderFrame>
+          chrome_render_frame,
       const WebApplicationInfo& web_app_info);
 
   // Accessors, etc.
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
index 4acdcae3..ad607815 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
@@ -248,7 +248,9 @@
     WebApplicationInfo web_application_info;
     web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
 
-    fetcher->OnDidGetWebApplicationInfo(nullptr, web_application_info);
+    fetcher->OnDidGetWebApplicationInfo(
+        mojo::AssociatedRemote<chrome::mojom::ChromeRenderFrame>(),
+        web_application_info);
     waiter.WaitForDataAvailable();
 
     EXPECT_EQ(is_webapk_compatible, waiter.is_webapk_compatible());
diff --git a/chrome/browser/apps/app_service/extension_apps.cc b/chrome/browser/apps/app_service/extension_apps.cc
index 5d1c31f..78437581 100644
--- a/chrome/browser/apps/app_service/extension_apps.cc
+++ b/chrome/browser/apps/app_service/extension_apps.cc
@@ -412,16 +412,12 @@
     case extensions::UnloadedExtensionReason::DISABLE:
       readiness = apps::mojom::Readiness::kDisabledByUser;
       break;
-
-    // TODO: Check the process for other status, and set the correct value to
-    // app->readiness. AppServiceAppModelBuilder::OnAppUpdate should be updated
-    // to show the correct icon status in app list.
     case extensions::UnloadedExtensionReason::BLACKLIST:
       readiness = apps::mojom::Readiness::kDisabledByBlacklist;
-      return;
+      break;
     case extensions::UnloadedExtensionReason::TERMINATE:
       readiness = apps::mojom::Readiness::kTerminated;
-      return;
+      break;
     case extensions::UnloadedExtensionReason::UNINSTALL:
       readiness = apps::mojom::Readiness::kUninstalledByUser;
       return;
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 945f1bb..cc08145 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -22,6 +22,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/test_mock_time_task_runner.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
@@ -52,7 +53,7 @@
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
-#include "components/download/public/common/download_features.h"
+#include "components/download/public/common/download_task_runner.h"
 #include "components/guest_view/browser/guest_view_manager.h"
 #include "components/guest_view/browser/guest_view_manager_delegate.h"
 #include "components/guest_view/browser/guest_view_manager_factory.h"
@@ -2745,57 +2746,34 @@
   return std::move(response);
 }
 
-class DownloadHistoryWaiter : public DownloadHistory::Observer {
+// Class for waiting for download manager to be initiailized.
+class DownloadManagerWaiter : public content::DownloadManager::Observer {
  public:
-  explicit DownloadHistoryWaiter(content::BrowserContext* browser_context) {
-    DownloadCoreService* service =
-        DownloadCoreServiceFactory::GetForBrowserContext(browser_context);
-    download_history_ = service->GetDownloadHistory();
-    download_history_->AddObserver(this);
+  explicit DownloadManagerWaiter(content::DownloadManager* download_manager)
+      : initialized_(false), download_manager_(download_manager) {
+    download_manager_->AddObserver(this);
   }
 
-  ~DownloadHistoryWaiter() override { download_history_->RemoveObserver(this); }
+  ~DownloadManagerWaiter() override { download_manager_->RemoveObserver(this); }
 
-  void WaitForStored(size_t download_count) {
-    if (stored_downloads_.size() >= download_count)
+  void WaitForInitialized() {
+    if (initialized_)
       return;
-    stored_download_target_ = download_count;
-    Wait();
-  }
-
-  void WaitForHistoryLoad() {
-    if (history_query_complete_)
-      return;
-    Wait();
-  }
-
- private:
-  void Wait() {
     base::RunLoop run_loop;
     quit_closure_ = run_loop.QuitClosure();
     run_loop.Run();
   }
 
-  void OnDownloadStored(download::DownloadItem* item,
-                        const history::DownloadRow& info) override {
-    stored_downloads_.insert(item);
-    if (!quit_closure_.is_null() &&
-        stored_downloads_.size() >= stored_download_target_) {
-      std::move(quit_closure_).Run();
-    }
-  }
-
-  void OnHistoryQueryComplete() override {
-    history_query_complete_ = true;
-    if (!quit_closure_.is_null())
+  void OnManagerInitialized() override {
+    initialized_ = true;
+    if (quit_closure_)
       std::move(quit_closure_).Run();
   }
 
-  std::unordered_set<download::DownloadItem*> stored_downloads_;
-  size_t stored_download_target_ = 0;
-  bool history_query_complete_ = false;
+ private:
   base::Closure quit_closure_;
-  DownloadHistory* download_history_ = nullptr;
+  bool initialized_;
+  content::DownloadManager* download_manager_;
 };
 
 }  // namespace
@@ -2894,15 +2872,14 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebViewTest, PRE_DownloadCookieIsolation_CrossSession) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(
-      download::features::kDownloadDBForNewDownloads);
-
   embedded_test_server()->RegisterRequestHandler(
       base::BindRepeating(&HandleDownloadRequestWithCookie));
   ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
   LoadAndLaunchPlatformApp("web_view/download_cookie_isolation",
                            "created-webviews");
+  scoped_refptr<base::TestMockTimeTaskRunner> task_runner(
+      new base::TestMockTimeTaskRunner);
+  download::SetDownloadDBTaskRunnerForTesting(task_runner);
 
   content::WebContents* web_contents = GetFirstAppWindowWebContents();
   ASSERT_TRUE(web_contents);
@@ -2910,9 +2887,6 @@
   content::DownloadManager* download_manager =
       content::BrowserContext::GetDownloadManager(
           web_contents->GetBrowserContext());
-
-  DownloadHistoryWaiter history_waiter(web_contents->GetBrowserContext());
-
   std::unique_ptr<content::DownloadTestObserver> interrupted_observer(
       new content::DownloadTestObserverInterrupted(
           download_manager, 2,
@@ -2945,7 +2919,7 @@
   interrupted_observer->WaitForFinished();
 
   // Wait for both downloads to be stored.
-  history_waiter.WaitForStored(2);
+  task_runner->FastForwardUntilNoTasksRemain();
 
   content::EnsureCookiesFlushed(profile());
 }
@@ -2961,21 +2935,21 @@
 
 IN_PROC_BROWSER_TEST_F(WebViewTest,
                        MAYBE_DownloadCookieIsolation_CrossSession) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(
-      download::features::kDownloadDBForNewDownloads);
-
   embedded_test_server()->RegisterRequestHandler(
       base::BindRepeating(&HandleDownloadRequestWithCookie));
   ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
 
+  scoped_refptr<base::TestMockTimeTaskRunner> task_runner(
+      new base::TestMockTimeTaskRunner);
+  download::SetDownloadDBTaskRunnerForTesting(task_runner);
+
   content::BrowserContext* browser_context = profile();
   content::DownloadManager* download_manager =
       content::BrowserContext::GetDownloadManager(browser_context);
 
-  DownloadHistoryWaiter history_waiter(browser_context);
-  history_waiter.WaitForHistoryLoad();
-
+  task_runner->FastForwardUntilNoTasksRemain();
+  DownloadManagerWaiter waiter(download_manager);
+  waiter.WaitForInitialized();
   content::DownloadManager::DownloadVector saved_downloads;
   download_manager->GetAllDownloads(&saved_downloads);
   ASSERT_EQ(2u, saved_downloads.size());
@@ -3018,7 +2992,7 @@
     ASSERT_TRUE(download->GetFullPath().empty());
     EXPECT_EQ(download::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED,
               download->GetLastReason());
-    download->Resume(false);
+    download->Resume(true);
   }
 
   completion_observer->WaitForFinished();
diff --git a/chrome/browser/banners/app_banner_manager_android.cc b/chrome/browser/banners/app_banner_manager_android.cc
index a70ca611..1b894e0 100644
--- a/chrome/browser/banners/app_banner_manager_android.cc
+++ b/chrome/browser/banners/app_banner_manager_android.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/banners/app_banner_ui_delegate_android.h"
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/installable/installable_metrics.h"
 #include "chrome/common/chrome_features.h"
 #include "components/infobars/core/infobar.h"
 #include "components/infobars/core/infobar_delegate.h"
@@ -216,7 +217,11 @@
         primary_icon_, native_app_package_);
   }
 
-  HideAmbientBadge();
+  // If we are installing from the ambient badge, it will remove itself.
+  if (install_source != WebappInstallSource::AMBIENT_BADGE_CUSTOM_TAB &&
+      install_source != WebappInstallSource::AMBIENT_BADGE_BROWSER_TAB) {
+    HideAmbientBadge();
+  }
 
   if (ui_delegate_->ShowDialog()) {
     if (native_app_data_.is_null()) {
@@ -365,6 +370,9 @@
 
   InfoBarService* infobar_service =
       InfoBarService::FromWebContents(web_contents());
+  if (infobar_service == nullptr)
+    return;
+
   if (GetVisibleAmbientBadgeInfoBar(infobar_service) == nullptr) {
     InstallableAmbientBadgeInfoBarDelegate::Create(
         web_contents(), weak_factory_.GetWeakPtr(), GetAppName(), primary_icon_,
@@ -375,6 +383,9 @@
 void AppBannerManagerAndroid::HideAmbientBadge() {
   InfoBarService* infobar_service =
       InfoBarService::FromWebContents(web_contents());
+  if (infobar_service == nullptr)
+    return;
+
   infobars::InfoBar* ambient_badge_infobar =
       GetVisibleAmbientBadgeInfoBar(infobar_service);
 
diff --git a/chrome/browser/browser_switcher/bho/BUILD.gn b/chrome/browser/browser_switcher/bho/BUILD.gn
index 66a05b4..05568ae 100644
--- a/chrome/browser/browser_switcher/bho/BUILD.gn
+++ b/chrome/browser/browser_switcher/bho/BUILD.gn
@@ -83,7 +83,6 @@
   ]
   deps = [
     "//base",
-    "//base/test:test_support",
     "//testing/gtest",
   ]
 }
diff --git a/chrome/browser/browser_switcher/bho/mini_bho_util_unittest.cc b/chrome/browser/browser_switcher/bho/mini_bho_util_unittest.cc
index 38c4d0d6..10c5592 100644
--- a/chrome/browser/browser_switcher/bho/mini_bho_util_unittest.cc
+++ b/chrome/browser/browser_switcher/bho/mini_bho_util_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/test_suite.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -39,13 +38,13 @@
   util::SetLogFilePathForTesting(log_path.value().c_str());
   util::InitLog();
 
-  util::puts(INFO, "hello world");
+  util::puts(DEBUG, "hello world");
   util::printf(ERR, "n = %d\n", 34);
 
   util::CloseLog();
 
   const char expected[] =
-      "[info] : hello world\n"
+      "[debug] : hello world\n"
       "[*ERROR!*] : n = 34\n";
 
   EXPECT_TRUE(base::PathExists(log_path));
@@ -183,5 +182,6 @@
 }
 
 int main(int argc, char** argv) {
-  base::RunUnitTestsUsingBaseTestSuite(argc, argv);
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
 }
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 5bc2752..13604ed 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1049,14 +1049,10 @@
     "file_system_provider/throttled_file_system.h",
     "file_system_provider/watcher.cc",
     "file_system_provider/watcher.h",
-    "fileapi/external_file_protocol_handler.cc",
-    "fileapi/external_file_protocol_handler.h",
     "fileapi/external_file_resolver.cc",
     "fileapi/external_file_resolver.h",
     "fileapi/external_file_url_loader_factory.cc",
     "fileapi/external_file_url_loader_factory.h",
-    "fileapi/external_file_url_request_job.cc",
-    "fileapi/external_file_url_request_job.h",
     "fileapi/external_file_url_util.cc",
     "fileapi/external_file_url_util.h",
     "fileapi/file_access_permissions.cc",
@@ -2578,7 +2574,6 @@
     "file_system_provider/service_unittest.cc",
     "file_system_provider/throttled_file_system_unittest.cc",
     "fileapi/external_file_url_loader_factory_unittest.cc",
-    "fileapi/external_file_url_request_job_unittest.cc",
     "fileapi/external_file_url_util_unittest.cc",
     "fileapi/file_access_permissions_unittest.cc",
     "fileapi/file_system_backend_unittest.cc",
diff --git a/chrome/browser/chromeos/arc/file_system_watcher/arc_file_system_watcher_service_unittest.cc b/chrome/browser/chromeos/arc/file_system_watcher/arc_file_system_watcher_service_unittest.cc
index 2c627025..0c86f41 100644
--- a/chrome/browser/chromeos/arc/file_system_watcher/arc_file_system_watcher_service_unittest.cc
+++ b/chrome/browser/chromeos/arc/file_system_watcher/arc_file_system_watcher_service_unittest.cc
@@ -78,6 +78,12 @@
       &android_path));
   EXPECT_EQ("/storage", android_path.value());
 
+  // Error: |cros_path| is a parent of /media/removable.
+  android_path = base::FilePath(FILE_PATH_LITERAL("/storage"));
+  EXPECT_FALSE(AppendRelativePathForRemovableMedia(
+      base::FilePath(FILE_PATH_LITERAL("/media")), &android_path));
+  EXPECT_EQ("/storage", android_path.value());
+
   // Error: |cros_path| does not contain a component for device label.
   android_path = base::FilePath(FILE_PATH_LITERAL("/storage"));
   EXPECT_FALSE(AppendRelativePathForRemovableMedia(
diff --git a/chrome/browser/chromeos/arc/voice_interaction/voice_interaction_controller_client.cc b/chrome/browser/chromeos/arc/voice_interaction/voice_interaction_controller_client.cc
index affaab8..ca2b67f6 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/voice_interaction_controller_client.cc
+++ b/chrome/browser/chromeos/arc/voice_interaction/voice_interaction_controller_client.cc
@@ -39,7 +39,7 @@
   arc::ArcSessionManager::Get()->AddObserver(this);
   user_manager::UserManager::Get()->AddSessionStateObserver(this);
 
-  voice_interaction_state_ = ash::mojom::VoiceInteractionState::NOT_READY;
+  assistant_state_ = ash::mojom::AssistantState::NOT_READY;
 }
 
 VoiceInteractionControllerClient::~VoiceInteractionControllerClient() {
@@ -64,8 +64,8 @@
 }
 
 void VoiceInteractionControllerClient::NotifyStatusChanged(
-    ash::mojom::VoiceInteractionState state) {
-  voice_interaction_state_ = state;
+    ash::mojom::AssistantState state) {
+  assistant_state_ = state;
   ash::AssistantState::Get()->NotifyStatusChanged(state);
   for (auto& observer : observers_)
     observer.OnStateChanged(state);
diff --git a/chrome/browser/chromeos/arc/voice_interaction/voice_interaction_controller_client.h b/chrome/browser/chromeos/arc/voice_interaction/voice_interaction_controller_client.h
index 12937b6..acaf8da8 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/voice_interaction_controller_client.h
+++ b/chrome/browser/chromeos/arc/voice_interaction/voice_interaction_controller_client.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
+#include "ash/public/mojom/assistant_state_controller.mojom.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/arc/arc_session_manager.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -26,7 +26,7 @@
   class Observer {
    public:
     // Called when voice interaction session state changes.
-    virtual void OnStateChanged(ash::mojom::VoiceInteractionState state) = 0;
+    virtual void OnStateChanged(ash::mojom::AssistantState state) = 0;
   };
 
   VoiceInteractionControllerClient();
@@ -34,15 +34,15 @@
   static VoiceInteractionControllerClient* Get();
 
   // Notify the controller about state changes.
-  void NotifyStatusChanged(ash::mojom::VoiceInteractionState state);
+  void NotifyStatusChanged(ash::mojom::AssistantState state);
 
   void NotifyLockedFullScreenStateChanged(bool enabled);
 
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
-  const ash::mojom::VoiceInteractionState& voice_interaction_state() const {
-    return voice_interaction_state_;
+  const ash::mojom::AssistantState& assistant_state() const {
+    return assistant_state_;
   }
 
  private:
@@ -65,8 +65,8 @@
 
   Profile* profile_ = nullptr;
 
-  ash::mojom::VoiceInteractionState voice_interaction_state_ =
-      ash::mojom::VoiceInteractionState::STOPPED;
+  ash::mojom::AssistantState assistant_state_ =
+      ash::mojom::AssistantState::READY;
 
   base::ObserverList<Observer>::Unchecked observers_;
 
diff --git a/chrome/browser/chromeos/assistant/assistant_util.cc b/chrome/browser/chromeos/assistant/assistant_util.cc
index e9b0df1..cd0e0445 100644
--- a/chrome/browser/chromeos/assistant/assistant_util.cc
+++ b/chrome/browser/chromeos/assistant/assistant_util.cc
@@ -6,7 +6,6 @@
 
 #include <string>
 
-#include "ash/public/mojom/voice_interaction_controller.mojom-shared.h"
 #include "base/strings/string_util.h"
 #include "base/system/sys_info.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
diff --git a/chrome/browser/chromeos/assistant/assistant_util.h b/chrome/browser/chromeos/assistant/assistant_util.h
index 8bc01ff..cb4ec59 100644
--- a/chrome/browser/chromeos/assistant/assistant_util.h
+++ b/chrome/browser/chromeos/assistant/assistant_util.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_ASSISTANT_ASSISTANT_UTIL_H_
 #define CHROME_BROWSER_CHROMEOS_ASSISTANT_ASSISTANT_UTIL_H_
 
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
+#include "ash/public/mojom/assistant_state_controller.mojom.h"
 
 class Profile;
 
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index 33734cc3..92063d8 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -122,10 +122,11 @@
 
 class CrostiniManager::CrostiniRestarter
     : public base::RefCountedThreadSafe<CrostiniRestarter>,
+      public crostini::VmShutdownObserver,
       public chromeos::disks::DiskMountManager::Observer {
  public:
   CrostiniRestarter(Profile* profile,
-                    base::WeakPtr<CrostiniManager> crostini_manager,
+                    CrostiniManager* crostini_manager,
                     std::string vm_name,
                     std::string container_name,
                     CrostiniManager::CrostiniResultCallback callback)
@@ -134,7 +135,9 @@
         vm_name_(std::move(vm_name)),
         container_name_(std::move(container_name)),
         completed_callback_(std::move(callback)),
-        restart_id_(next_restart_id_++) {}
+        restart_id_(next_restart_id_++) {
+    crostini_manager_->AddVmShutdownObserver(this);
+  }
 
   void Restart() {
     is_initial_install_ = crostini_manager_->GetInstallerViewStatus();
@@ -171,6 +174,14 @@
     std::move(completed_callback_).Run(result);
   }
 
+  // crostini::VmShutdownObserver
+  void OnVmShutdown(const std::string& vm_name) override {
+    if (vm_name == vm_name_) {
+      LOG(WARNING) << "Unexpected VM shutdown during restart for " << vm_name;
+      FinishRestart(CrostiniResult::RESTART_FAILED_VM_STOPPED);
+    }
+  }
+
   void Abort(base::OnceClosure callback) {
     is_aborted_ = true;
     observer_list_.Clear();
@@ -196,6 +207,7 @@
   friend class base::RefCountedThreadSafe<CrostiniRestarter>;
 
   ~CrostiniRestarter() override {
+    crostini_manager_->RemoveVmShutdownObserver(this);
     if (completed_callback_) {
       LOG(ERROR) << "Destroying without having called the callback.";
     }
@@ -367,12 +379,6 @@
 
   void StartLxdContainerFinished(CrostiniResult result) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-    // The restarter shouldn't outlive the CrostiniManager but it can when
-    // skip_restart_for_testing is set.
-    if (!crostini_manager_) {
-      LOG(ERROR) << "CrostiniManager deleted";
-      return;
-    }
 
     CloseCrostiniUpgradeContainerView();
     for (auto& observer : observer_list_) {
@@ -444,6 +450,7 @@
                     chromeos::MOUNT_ACCESS_MODE_READ_WRITE);
   }
 
+  // chromeos::disks::DiskMountManager::Observer
   void OnMountEvent(chromeos::disks::DiskMountManager::MountEvent event,
                     chromeos::MountError error_code,
                     const chromeos::disks::DiskMountManager::MountPointInfo&
@@ -493,9 +500,9 @@
   }
 
   Profile* profile_;
-  // This isn't accessed after the CrostiniManager is destroyed, but we still
-  // use a WeakPtr for safety.
-  base::WeakPtr<CrostiniManager> crostini_manager_;
+  // This isn't accessed after the CrostiniManager is destroyed and we need a
+  // reference to it during the CrostiniRestarter destructor.
+  CrostiniManager* crostini_manager_;
 
   std::string vm_name_;
   std::string container_name_;
@@ -633,6 +640,7 @@
     : profile_(profile), owner_id_(CryptohomeIdForProfile(profile)) {
   DCHECK(!profile_->IsOffTheRecord());
   GetCiceroneClient()->AddObserver(this);
+  GetConciergeClient()->AddVmObserver(this);
   GetConciergeClient()->AddContainerObserver(this);
   if (chromeos::PowerManagerClient::Get()) {
     chromeos::PowerManagerClient::Get()->AddObserver(this);
@@ -1634,8 +1642,8 @@
   }
 
   auto restarter = base::MakeRefCounted<CrostiniRestarter>(
-      profile_, weak_ptr_factory_.GetWeakPtr(), std::move(vm_name),
-      std::move(container_name), std::move(callback));
+      profile_, this, std::move(vm_name), std::move(container_name),
+      std::move(callback));
   if (observer)
     restarter->AddObserver(observer);
   auto key = std::make_pair(restarter->vm_name(), restarter->container_name());
@@ -1919,6 +1927,11 @@
     }
   }
 
+  OnVmStoppedCleanup(vm_name);
+  std::move(callback).Run(CrostiniResult::SUCCESS);
+}
+
+void CrostiniManager::OnVmStoppedCleanup(const std::string& vm_name) {
   for (auto& observer : vm_shutdown_observers_) {
     observer.OnVmShutdown(vm_name);
   }
@@ -1932,7 +1945,6 @@
   InvokeAndErasePendingCallbacks(
       &import_lxd_container_callbacks_, vm_name,
       CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED);
-  std::move(callback).Run(CrostiniResult::SUCCESS);
 }
 
 void CrostiniManager::OnGetTerminaVmKernelVersion(
@@ -2001,6 +2013,16 @@
       kCrostiniDefaultContainerName, result);
 }
 
+void CrostiniManager::OnVmStarted(
+    const vm_tools::concierge::VmStartedSignal& signal) {}
+
+void CrostiniManager::OnVmStopped(
+    const vm_tools::concierge::VmStoppedSignal& signal) {
+  if (signal.owner_id() != owner_id_)
+    return;
+  OnVmStoppedCleanup(signal.name());
+}
+
 void CrostiniManager::OnContainerStartupFailed(
     const vm_tools::concierge::ContainerStartedSignal& signal) {
   if (signal.owner_id() != owner_id_)
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h
index fa1ca9f..1cabdb9 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.h
+++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -115,6 +115,7 @@
 // possible. The existence of Cicerone is abstracted behind this class and
 // only the Concierge name is exposed outside of here.
 class CrostiniManager : public KeyedService,
+                        public chromeos::ConciergeClient::VmObserver,
                         public chromeos::ConciergeClient::ContainerObserver,
                         public chromeos::CiceroneClient::Observer,
                         public chromeos::PowerManagerClient::Observer {
@@ -429,7 +430,11 @@
   void AddVmShutdownObserver(VmShutdownObserver* observer);
   void RemoveVmShutdownObserver(VmShutdownObserver* observer);
 
-  // ConciergeClient::Observer:
+  // ConciergeClient::VmObserver:
+  void OnVmStarted(const vm_tools::concierge::VmStartedSignal& signal) override;
+  void OnVmStopped(const vm_tools::concierge::VmStoppedSignal& signal) override;
+
+  // ConciergeClient::ContainerObserver:
   void OnContainerStartupFailed(
       const vm_tools::concierge::ContainerStartedSignal& signal) override;
 
@@ -714,6 +719,8 @@
   // Callback for CrostiniManager::RemoveCrostini.
   void OnRemoveCrostini(CrostiniResult result);
 
+  void OnVmStoppedCleanup(const std::string& vm_name);
+
   Profile* profile_;
   std::string owner_id_;
 
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
index cb7503e..57760bf 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -16,6 +16,8 @@
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/testing_profile.h"
+#include "chromeos/dbus/cicerone/cicerone_service.pb.h"
+#include "chromeos/dbus/concierge/service.pb.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cicerone_client.h"
 #include "chromeos/dbus/fake_concierge_client.h"
@@ -1070,6 +1072,24 @@
   EXPECT_EQ(1, remove_crostini_callback_count_);
 }
 
+TEST_F(CrostiniManagerRestartTest, VmStoppedDuringRestart) {
+  fake_cicerone_client_->set_send_container_started_signal(false);
+  restart_id_ = crostini_manager()->RestartCrostini(
+      kVmName, kContainerName,
+      base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback,
+                     base::Unretained(this), run_loop()->QuitClosure()),
+      this);
+  run_loop()->RunUntilIdle();
+  EXPECT_TRUE(crostini_manager()->IsRestartPending(restart_id_));
+  EXPECT_EQ(0, restart_crostini_callback_count_);
+  vm_tools::concierge::VmStoppedSignal vm_stopped_signal;
+  vm_stopped_signal.set_owner_id(CryptohomeIdForProfile(profile()));
+  vm_stopped_signal.set_name(kVmName);
+  crostini_manager()->OnVmStopped(vm_stopped_signal);
+  EXPECT_FALSE(crostini_manager()->IsRestartPending(restart_id_));
+  EXPECT_EQ(1, restart_crostini_callback_count_);
+}
+
 class CrostiniManagerEnterpriseReportingTest
     : public CrostiniManagerRestartTest {
  public:
diff --git a/chrome/browser/chromeos/crostini/crostini_package_service_unittest.cc b/chrome/browser/chromeos/crostini/crostini_package_service_unittest.cc
index 194d444..534737a 100644
--- a/chrome/browser/chromeos/crostini/crostini_package_service_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_package_service_unittest.cc
@@ -205,6 +205,8 @@
   }
 
   void TearDown() override {
+    // Complete all CrostiniManager queued tasks before deleting it.
+    base::RunLoop().RunUntilIdle();
     service_.reset();
     notification_display_service_tester_.reset();
     crostini_test_helper_.reset();
diff --git a/chrome/browser/chromeos/crostini/crostini_simple_types.h b/chrome/browser/chromeos/crostini/crostini_simple_types.h
index 44a15ac5..9f38e22 100644
--- a/chrome/browser/chromeos/crostini/crostini_simple_types.h
+++ b/chrome/browser/chromeos/crostini/crostini_simple_types.h
@@ -62,7 +62,8 @@
   GET_CONTAINER_SSH_KEYS_FAILED = 36,
   CONTAINER_EXPORT_IMPORT_CANCELLED = 37,
   RESTART_ABORTED = 38,
-  kMaxValue = RESTART_ABORTED,
+  RESTART_FAILED_VM_STOPPED = 39,
+  kMaxValue = RESTART_FAILED_VM_STOPPED,
 };
 
 enum class InstallLinuxPackageProgressStatus {
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 2b162c8..19cb639 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -1667,9 +1667,9 @@
   // |RUNNING| means service running with UI shown on screen.
   // When enabling Assistant, either |STOPPED| or |RUNNING| state could be
   // possible depending on whether the UI has been brought up.
-  auto current_state = ash::AssistantState::Get()->voice_interaction_state();
+  auto current_state = ash::AssistantState::Get()->assistant_state();
   const bool not_ready =
-      (current_state == ash::mojom::VoiceInteractionState::NOT_READY);
+      (current_state == ash::mojom::AssistantState::NOT_READY);
   const bool success = (params->enabled != not_ready);
   if (success)
     return RespondNow(NoArguments());
@@ -1686,7 +1686,7 @@
 }
 
 void AutotestPrivateSetAssistantEnabledFunction::OnAssistantStatusChanged(
-    ash::mojom::VoiceInteractionState state) {
+    ash::mojom::AssistantState state) {
   // Must check if the Optional contains value first to avoid possible
   // segmentation fault caused by Respond() below being called before
   // RespondLater() in Run(). This will happen due to AddObserver() call
@@ -1696,8 +1696,7 @@
 
   // The service could go through |NOT_READY| then to |STOPPED| during enable
   // flow if this API is called before the initial state is reported.
-  const bool not_ready =
-      (state == ash::mojom::VoiceInteractionState::NOT_READY);
+  const bool not_ready = (state == ash::mojom::AssistantState::NOT_READY);
   const bool success = (enabled_.value() != not_ready);
   if (!success)
     return;
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
index 791d44c8..a43e038 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
@@ -498,8 +498,7 @@
   ResponseAction Run() override;
 
   // ash::AssistantStateObserver overrides:
-  void OnAssistantStatusChanged(
-      ash::mojom::VoiceInteractionState state) override;
+  void OnAssistantStatusChanged(ash::mojom::AssistantState state) override;
 
   // Called when the Assistant service does not respond in a timely fashion. We
   // will respond with an error.
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
index 24d0128..2310917 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -56,8 +56,6 @@
   dict->SetBoolean("CROSTINI_ROOT_ACCESS_ALLOWED",
                    crostini::IsCrostiniRootAccessAllowed(
                        Profile::FromBrowserContext(browser_context())));
-  dict->SetBoolean("DRIVE_FS_ENABLED",
-                   base::FeatureList::IsEnabled(chromeos::features::kDriveFs));
   dict->SetBoolean("FEEDBACK_PANEL_ENABLED",
                    base::FeatureList::IsEnabled(
                        chromeos::features::kEnableFileManagerFeedbackPanel));
diff --git a/chrome/browser/chromeos/fileapi/external_file_protocol_handler.cc b/chrome/browser/chromeos/fileapi/external_file_protocol_handler.cc
deleted file mode 100644
index 21eefc7..0000000
--- a/chrome/browser/chromeos/fileapi/external_file_protocol_handler.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/fileapi/external_file_protocol_handler.h"
-
-#include "base/logging.h"
-#include "chrome/browser/chromeos/fileapi/external_file_url_request_job.h"
-#include "net/url_request/url_request.h"
-#include "url/gurl.h"
-
-namespace chromeos {
-
-ExternalFileProtocolHandler::ExternalFileProtocolHandler(void* profile_id)
-    : profile_id_(profile_id) {
-}
-
-ExternalFileProtocolHandler::~ExternalFileProtocolHandler() {
-}
-
-net::URLRequestJob* ExternalFileProtocolHandler::MaybeCreateJob(
-    net::URLRequest* request,
-    net::NetworkDelegate* network_delegate) const {
-  DVLOG(1) << "Handling url: " << request->url().spec();
-  return new ExternalFileURLRequestJob(profile_id_, request, network_delegate);
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/fileapi/external_file_protocol_handler.h b/chrome/browser/chromeos/fileapi/external_file_protocol_handler.h
deleted file mode 100644
index f3f4a42..0000000
--- a/chrome/browser/chromeos/fileapi/external_file_protocol_handler.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_FILEAPI_EXTERNAL_FILE_PROTOCOL_HANDLER_H_
-#define CHROME_BROWSER_CHROMEOS_FILEAPI_EXTERNAL_FILE_PROTOCOL_HANDLER_H_
-
-#include "base/macros.h"
-#include "net/url_request/url_request_job_factory.h"
-
-namespace chromeos {
-
-class ExternalFileProtocolHandler
-    : public net::URLRequestJobFactory::ProtocolHandler {
- public:
-  explicit ExternalFileProtocolHandler(void* profile_id);
-  ~ExternalFileProtocolHandler() override;
-
-  // Creates URLRequestJobs for drive:// URLs.
-  net::URLRequestJob* MaybeCreateJob(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override;
-
- private:
-  // The profile for processing Drive accesses. Should not be NULL.
-  void* profile_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(ExternalFileProtocolHandler);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_FILEAPI_EXTERNAL_FILE_PROTOCOL_HANDLER_H_
diff --git a/chrome/browser/chromeos/fileapi/external_file_url_request_job.cc b/chrome/browser/chromeos/fileapi/external_file_url_request_job.cc
deleted file mode 100644
index 600d282..0000000
--- a/chrome/browser/chromeos/fileapi/external_file_url_request_job.cc
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/fileapi/external_file_url_request_job.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/task/post_task.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/base/net_errors.h"
-#include "net/url_request/url_request_status.h"
-#include "storage/browser/fileapi/file_stream_reader.h"
-
-using content::BrowserThread;
-
-namespace chromeos {
-
-ExternalFileURLRequestJob::ExternalFileURLRequestJob(
-    void* profile_id,
-    net::URLRequest* request,
-    net::NetworkDelegate* network_delegate)
-    : net::URLRequestJob(request, network_delegate),
-      resolver_(std::make_unique<ExternalFileResolver>(profile_id)) {}
-
-void ExternalFileURLRequestJob::SetExtraRequestHeaders(
-    const net::HttpRequestHeaders& headers) {
-  resolver_->ProcessHeaders(headers);
-}
-
-void ExternalFileURLRequestJob::Start() {
-  // Post a task to invoke StartAsync asynchronously to avoid re-entering the
-  // delegate, because NotifyStartError is not legal to call synchronously in
-  // Start().
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&ExternalFileURLRequestJob::StartAsync,
-                                weak_ptr_factory_.GetWeakPtr()));
-}
-
-void ExternalFileURLRequestJob::StartAsync() {
-  DVLOG(1) << "Starting request";
-  DCHECK(!stream_reader_);
-  resolver_->Resolve(
-      request()->method(), request()->url(),
-      base::BindOnce(&ExternalFileURLRequestJob::OnError,
-                     weak_ptr_factory_.GetWeakPtr()),
-      base::BindOnce(&ExternalFileURLRequestJob::OnRedirectURLObtained,
-                     weak_ptr_factory_.GetWeakPtr()),
-      base::BindOnce(&ExternalFileURLRequestJob::OnStreamObtained,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void ExternalFileURLRequestJob::OnRedirectURLObtained(
-    const std::string& mime_type,
-    const GURL& redirect_url) {
-  mime_type_ = mime_type;
-  redirect_url_ = redirect_url;
-  NotifyHeadersComplete();
-}
-
-void ExternalFileURLRequestJob::OnStreamObtained(
-    const std::string& mime_type,
-    storage::IsolatedContext::ScopedFSHandle isolated_file_system_scope,
-    std::unique_ptr<storage::FileStreamReader> stream_reader,
-    int64_t size) {
-  mime_type_ = mime_type;
-  isolated_file_system_scope_ = std::move(isolated_file_system_scope);
-  stream_reader_ = std::move(stream_reader);
-  remaining_bytes_ = size;
-
-  set_expected_content_size(remaining_bytes_);
-  NotifyHeadersComplete();
-}
-
-void ExternalFileURLRequestJob::OnError(net::Error error) {
-  NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
-}
-
-void ExternalFileURLRequestJob::Kill() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  resolver_.reset();
-  stream_reader_.reset();
-  isolated_file_system_scope_ = {};
-  net::URLRequestJob::Kill();
-  weak_ptr_factory_.InvalidateWeakPtrs();
-}
-
-bool ExternalFileURLRequestJob::GetMimeType(std::string* mime_type) const {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  mime_type->assign(mime_type_);
-  return !mime_type->empty();
-}
-
-bool ExternalFileURLRequestJob::IsRedirectResponse(
-    GURL* location,
-    int* http_status_code,
-    bool* insecure_scheme_was_upgraded) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  if (redirect_url_.is_empty())
-    return false;
-
-  // Redirect a hosted document.
-  *insecure_scheme_was_upgraded = false;
-  *location = redirect_url_;
-  const int kHttpFound = 302;
-  *http_status_code = kHttpFound;
-  return true;
-}
-
-int ExternalFileURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK(stream_reader_);
-
-  if (remaining_bytes_ == 0)
-    return 0;
-
-  const int result = stream_reader_->Read(
-      buf, std::min<int64_t>(buf_size, remaining_bytes_),
-      base::Bind(&ExternalFileURLRequestJob::OnReadCompleted,
-                 weak_ptr_factory_.GetWeakPtr()));
-
-  if (result < 0)
-    return result;
-
-  remaining_bytes_ -= result;
-  return result;
-}
-
-ExternalFileURLRequestJob::~ExternalFileURLRequestJob() {
-}
-
-void ExternalFileURLRequestJob::OnReadCompleted(int read_result) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  if (read_result > 0)
-    remaining_bytes_ -= read_result;
-
-  ReadRawDataComplete(read_result);
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/fileapi/external_file_url_request_job.h b/chrome/browser/chromeos/fileapi/external_file_url_request_job.h
deleted file mode 100644
index e024561c..0000000
--- a/chrome/browser/chromeos/fileapi/external_file_url_request_job.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_FILEAPI_EXTERNAL_FILE_URL_REQUEST_JOB_H_
-#define CHROME_BROWSER_CHROMEOS_FILEAPI_EXTERNAL_FILE_URL_REQUEST_JOB_H_
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/chromeos/fileapi/external_file_resolver.h"
-#include "components/drive/file_errors.h"
-#include "net/base/net_errors.h"
-#include "net/url_request/url_request_job.h"
-#include "url/gurl.h"
-
-namespace net {
-class IOBuffer;
-class NetworkDelegate;
-class URLRequest;
-}  // namespace net
-namespace storage {
-class FileStreamReader;
-}
-
-namespace chromeos {
-
-// ExternalFileURLRequestJob is the gateway between network-level drive:...
-// requests for drive resources and FileSystem.  It exposes content URLs
-// formatted as drive:<drive-file-path>.
-// The methods should be run on IO thread.
-// TODO(hirono): After removing MHTML support, stop to use the special
-// externalfile: scheme and use filesystem: URL directly.  crbug.com/415455
-class ExternalFileURLRequestJob : public net::URLRequestJob {
- public:
-  ExternalFileURLRequestJob(void* profile_id,
-                            net::URLRequest* request,
-                            net::NetworkDelegate* network_delegate);
-
-  // net::URLRequestJob overrides:
-  void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
-  void Start() override;
-  void Kill() override;
-  bool GetMimeType(std::string* mime_type) const override;
-  bool IsRedirectResponse(GURL* location,
-                          int* http_status_code,
-                          bool* insecure_scheme_was_upgraded) override;
-  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
-
- protected:
-  ~ExternalFileURLRequestJob() override;
-
- private:
-  // Helper method to start the job. Should be called asynchronously because
-  // NotifyStartError() is not legal to call synchronously in
-  // URLRequestJob::Start().
-  void StartAsync();
-
-  void OnRedirectURLObtained(const std::string& mime_type,
-                             const GURL& redirect_url);
-
-  void OnStreamObtained(
-      const std::string& mime_type,
-      storage::IsolatedContext::ScopedFSHandle isolated_file_system_scope,
-      std::unique_ptr<storage::FileStreamReader> stream_reader,
-      int64_t size);
-
-  void OnError(net::Error error);
-
-  // Called when DriveFileStreamReader::Read is completed.
-  void OnReadCompleted(int read_result);
-
-  std::unique_ptr<ExternalFileResolver> resolver_;
-
-  std::string mime_type_;
-  storage::IsolatedContext::ScopedFSHandle isolated_file_system_scope_;
-  std::unique_ptr<storage::FileStreamReader> stream_reader_;
-  int64_t remaining_bytes_;
-  GURL redirect_url_;
-
-  // This should remain the last member so it'll be destroyed first and
-  // invalidate its weak pointers before other members are destroyed.
-  base::WeakPtrFactory<ExternalFileURLRequestJob> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(ExternalFileURLRequestJob);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_FILEAPI_EXTERNAL_FILE_URL_REQUEST_JOB_H_
diff --git a/chrome/browser/chromeos/fileapi/external_file_url_request_job_unittest.cc b/chrome/browser/chromeos/fileapi/external_file_url_request_job_unittest.cc
deleted file mode 100644
index 2cdcb7c..0000000
--- a/chrome/browser/chromeos/fileapi/external_file_url_request_job_unittest.cc
+++ /dev/null
@@ -1,393 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/fileapi/external_file_url_request_job.h"
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/files/file_util.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/run_loop.h"
-#include "base/threading/thread.h"
-#include "chrome/browser/chromeos/drive/drive_file_stream_reader.h"
-#include "chrome/browser/chromeos/drive/drive_integration_service.h"
-#include "chrome/browser/chromeos/drive/file_system_util.h"
-#include "chrome/browser/chromeos/file_system_provider/fake_extension_provider.h"
-#include "chrome/browser/chromeos/file_system_provider/service.h"
-#include "chrome/browser/chromeos/file_system_provider/service_factory.h"
-#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
-#include "chrome/browser/prefs/browser_prefs.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/testing_profile.h"
-#include "chrome/test/base/testing_profile_manager.h"
-#include "chromeos/constants/chromeos_features.h"
-#include "components/drive/chromeos/drive_test_util.h"
-#include "components/drive/chromeos/fake_file_system.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "components/drive/service/test_util.h"
-#include "components/pref_registry/pref_registry_syncable.h"
-#include "components/sync_preferences/pref_service_syncable.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/common/url_constants.h"
-#include "content/public/test/browser_task_environment.h"
-#include "content/public/test/test_service_manager_context.h"
-#include "google_apis/drive/test_util.h"
-#include "net/base/request_priority.h"
-#include "net/base/test_completion_callback.h"
-#include "net/http/http_byte_range.h"
-#include "net/url_request/redirect_info.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_test_util.h"
-#include "storage/browser/fileapi/external_mount_points.h"
-#include "storage/browser/fileapi/file_system_context.h"
-#include "storage/browser/test/test_file_system_options.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace chromeos {
-namespace {
-
-// A simple URLRequestJobFactory implementation to create
-// ExternalFileURLRequestJob.
-class TestURLRequestJobFactory : public net::URLRequestJobFactory {
- public:
-  explicit TestURLRequestJobFactory(void* profile_id)
-      : profile_id_(profile_id) {}
-
-  ~TestURLRequestJobFactory() override {}
-
-  // net::URLRequestJobFactory override:
-  net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
-      const std::string& scheme,
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    return new ExternalFileURLRequestJob(
-        profile_id_, request, network_delegate);
-  }
-
-  net::URLRequestJob* MaybeInterceptRedirect(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate,
-      const GURL& location) const override {
-    return nullptr;
-  }
-
-  net::URLRequestJob* MaybeInterceptResponse(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    return nullptr;
-  }
-
-  bool IsHandledProtocol(const std::string& scheme) const override {
-    return scheme == content::kExternalFileScheme;
-  }
-
-  bool IsSafeRedirectTarget(const GURL& location) const override {
-    return true;
-  }
-
- private:
-  void* const profile_id_;
-  DISALLOW_COPY_AND_ASSIGN(TestURLRequestJobFactory);
-};
-
-class TestDelegate : public net::TestDelegate {
- public:
-  TestDelegate() {}
-
-  const GURL& redirect_url() const { return redirect_url_; }
-
-  // net::TestDelegate override.
-  void OnReceivedRedirect(net::URLRequest* request,
-                          const net::RedirectInfo& redirect_info,
-                          bool* defer_redirect) override {
-    redirect_url_ = redirect_info.new_url;
-    net::TestDelegate::OnReceivedRedirect(request, redirect_info,
-                                          defer_redirect);
-  }
-
- private:
-  GURL redirect_url_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
-};
-
-constexpr char kExtensionId[] = "abc";
-constexpr char kFileSystemId[] = "test-filesystem";
-constexpr char kTestUrl[] =
-    "externalfile:abc:test-filesystem:test-user-hash/hello.txt";
-constexpr char kExpectedFileContents[] =
-    "This is a testing file. Lorem ipsum dolor sit amet est.";
-
-}  // namespace
-
-class ExternalFileURLRequestJobTest : public testing::Test {
- protected:
-  ExternalFileURLRequestJobTest()
-      : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP),
-        integration_service_factory_callback_(base::Bind(
-            &ExternalFileURLRequestJobTest::CreateDriveIntegrationService,
-            base::Unretained(this))),
-        fake_file_system_(NULL) {}
-
-  ~ExternalFileURLRequestJobTest() override {}
-
-  void SetUp() override {
-    // Create a testing profile.
-    profile_manager_.reset(
-        new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
-    ASSERT_TRUE(profile_manager_->SetUp());
-    user_manager_ = std::make_unique<chromeos::FakeChromeUserManager>();
-    Profile* const profile =
-        profile_manager_->CreateTestingProfile("test-user");
-    user_manager_->AddUser(
-        AccountId::FromUserEmailGaiaId(profile->GetProfileUserName(), "12345"));
-
-    auto* service = chromeos::file_system_provider::Service::Get(profile);
-    service->RegisterProvider(
-        chromeos::file_system_provider::FakeExtensionProvider::Create(
-            kExtensionId));
-    const auto kProviderId =
-        chromeos::file_system_provider::ProviderId::CreateFromExtensionId(
-            kExtensionId);
-    service->MountFileSystem(kProviderId,
-                             chromeos::file_system_provider::MountOptions(
-                                 kFileSystemId, "Test FileSystem"));
-
-    // Create the drive integration service for the profile.
-    integration_service_factory_scope_.reset(
-        new drive::DriveIntegrationServiceFactory::ScopedFactoryForTest(
-            &integration_service_factory_callback_));
-    drive::DriveIntegrationServiceFactory::GetForProfile(profile);
-
-    // Create the URL request job factory.
-    test_network_delegate_.reset(new net::TestNetworkDelegate);
-    test_url_request_job_factory_.reset(new TestURLRequestJobFactory(profile));
-    url_request_context_.reset(new net::URLRequestContext());
-    url_request_context_->set_job_factory(test_url_request_job_factory_.get());
-    url_request_context_->set_network_delegate(test_network_delegate_.get());
-    test_delegate_.reset(new TestDelegate);
-  }
-
-  void TearDown() override { profile_manager_.reset(); }
-
-  bool ReadDriveFileSync(const base::FilePath& file_path,
-                         std::string* out_content) {
-    std::unique_ptr<base::Thread> worker_thread(
-        new base::Thread("ReadDriveFileSync"));
-    if (!worker_thread->Start())
-      return false;
-
-    std::unique_ptr<drive::DriveFileStreamReader> reader(
-        new drive::DriveFileStreamReader(
-            base::Bind(&ExternalFileURLRequestJobTest::GetFileSystem,
-                       base::Unretained(this)),
-            worker_thread->task_runner().get()));
-    int error = net::ERR_FAILED;
-    std::unique_ptr<drive::ResourceEntry> entry;
-    {
-      base::RunLoop run_loop;
-      reader->Initialize(file_path,
-                         net::HttpByteRange(),
-                         google_apis::test_util::CreateQuitCallback(
-                             &run_loop,
-                             google_apis::test_util::CreateCopyResultCallback(
-                                 &error, &entry)));
-      run_loop.Run();
-    }
-    if (error != net::OK || !entry)
-      return false;
-
-    // Read data from the reader.
-    std::string content;
-    if (drive::test_util::ReadAllData(reader.get(), &content) != net::OK)
-      return false;
-
-    if (static_cast<size_t>(entry->file_info().size()) != content.size())
-      return false;
-
-    *out_content = content;
-    return true;
-  }
-
-  std::unique_ptr<net::URLRequestContext> url_request_context_;
-  std::unique_ptr<TestDelegate> test_delegate_;
-
- private:
-  // Create the drive integration service for the |profile|
-  drive::DriveIntegrationService* CreateDriveIntegrationService(
-      Profile* profile) {
-    drive::FakeDriveService* const drive_service = new drive::FakeDriveService;
-    if (!drive::test_util::SetUpTestEntries(drive_service))
-      return NULL;
-
-    const std::string& drive_mount_name =
-        drive::util::GetDriveMountPointPath(profile).BaseName().AsUTF8Unsafe();
-    storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
-        drive_mount_name,
-        storage::kFileSystemTypeDrive,
-        storage::FileSystemMountOption(),
-        drive::util::GetDriveMountPointPath(profile));
-    DCHECK(!fake_file_system_);
-    fake_file_system_ = new drive::test_util::FakeFileSystem(drive_service);
-    if (!drive_cache_dir_.CreateUniqueTempDir())
-      return NULL;
-    return new drive::DriveIntegrationService(
-        profile, nullptr, drive_service, drive_mount_name,
-        drive_cache_dir_.GetPath(), fake_file_system_);
-  }
-
-  drive::FileSystemInterface* GetFileSystem() { return fake_file_system_; }
-
-  content::BrowserTaskEnvironment task_environment_;
-  content::TestServiceManagerContext context_;
-  drive::DriveIntegrationServiceFactory::FactoryCallback
-      integration_service_factory_callback_;
-  std::unique_ptr<drive::DriveIntegrationServiceFactory::ScopedFactoryForTest>
-      integration_service_factory_scope_;
-  std::unique_ptr<drive::DriveIntegrationService> integration_service_;
-  drive::test_util::FakeFileSystem* fake_file_system_;
-
-  std::unique_ptr<net::TestNetworkDelegate> test_network_delegate_;
-  std::unique_ptr<TestURLRequestJobFactory> test_url_request_job_factory_;
-
-  std::unique_ptr<TestingProfileManager> profile_manager_;
-  std::unique_ptr<chromeos::FakeChromeUserManager> user_manager_;
-  base::ScopedTempDir drive_cache_dir_;
-  scoped_refptr<storage::FileSystemContext> file_system_context_;
-};
-
-TEST_F(ExternalFileURLRequestJobTest, NonGetMethod) {
-  std::unique_ptr<net::URLRequest> request(url_request_context_->CreateRequest(
-      GURL(kTestUrl), net::DEFAULT_PRIORITY, test_delegate_.get()));
-  request->set_method("POST");  // Set non "GET" method.
-  request->Start();
-
-  base::RunLoop().Run();
-
-  EXPECT_EQ(net::ERR_METHOD_NOT_SUPPORTED, test_delegate_->request_status());
-}
-
-TEST_F(ExternalFileURLRequestJobTest, RegularFile) {
-  {
-    std::unique_ptr<net::URLRequest> request(
-        url_request_context_->CreateRequest(
-            GURL(kTestUrl), net::DEFAULT_PRIORITY, test_delegate_.get()));
-    request->Start();
-
-    base::RunLoop().Run();
-
-    ASSERT_EQ(net::OK, test_delegate_->request_status());
-    std::string mime_type;
-    request->GetMimeType(&mime_type);
-    EXPECT_EQ("text/plain", mime_type);
-
-    EXPECT_EQ(kExpectedFileContents, test_delegate_->data_received());
-  }
-}
-
-TEST_F(ExternalFileURLRequestJobTest, HostedDocument) {
-  // Hosted documents are never opened via externalfile: URLs with DriveFS.
-  if (base::FeatureList::IsEnabled(chromeos::features::kDriveFs)) {
-    return;
-  }
-  // Open a gdoc file.
-  std::unique_ptr<net::URLRequest> request(url_request_context_->CreateRequest(
-      GURL("externalfile:drive-test-user-hash/root/Document 1 "
-           "excludeDir-test.gdoc"),
-      net::DEFAULT_PRIORITY, test_delegate_.get()));
-  request->Start();
-
-  test_delegate_->RunUntilRedirect();
-
-  // Make sure that a hosted document triggers redirection.
-  EXPECT_TRUE(request->is_redirecting());
-  EXPECT_TRUE(test_delegate_->redirect_url().is_valid());
-}
-
-TEST_F(ExternalFileURLRequestJobTest, RootDirectory) {
-  std::unique_ptr<net::URLRequest> request(url_request_context_->CreateRequest(
-      GURL("externalfile:abc:test-filesystem:test-user-hash/"),
-      net::DEFAULT_PRIORITY, test_delegate_.get()));
-  request->Start();
-
-  base::RunLoop().Run();
-
-  EXPECT_EQ(net::ERR_FAILED, test_delegate_->request_status());
-}
-
-TEST_F(ExternalFileURLRequestJobTest, NonExistingFile) {
-  std::unique_ptr<net::URLRequest> request(url_request_context_->CreateRequest(
-      GURL("externalfile:abc:test-filesystem:test-user-hash/"
-           "non-existing-file.txt"),
-      net::DEFAULT_PRIORITY, test_delegate_.get()));
-  request->Start();
-
-  base::RunLoop().Run();
-
-  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, test_delegate_->request_status());
-}
-
-TEST_F(ExternalFileURLRequestJobTest, WrongFormat) {
-  std::unique_ptr<net::URLRequest> request(url_request_context_->CreateRequest(
-      GURL("externalfile:"), net::DEFAULT_PRIORITY, test_delegate_.get()));
-  request->Start();
-
-  base::RunLoop().Run();
-
-  EXPECT_EQ(net::ERR_INVALID_URL, test_delegate_->request_status());
-}
-
-TEST_F(ExternalFileURLRequestJobTest, Cancel) {
-  std::unique_ptr<net::URLRequest> request(url_request_context_->CreateRequest(
-      GURL(kTestUrl), net::DEFAULT_PRIORITY, test_delegate_.get()));
-
-  // Start the request, and cancel it immediately after it.
-  request->Start();
-  request->Cancel();
-
-  base::RunLoop().Run();
-
-  EXPECT_EQ(net::ERR_ABORTED, test_delegate_->request_status());
-}
-
-TEST_F(ExternalFileURLRequestJobTest, RangeHeader) {
-  std::unique_ptr<net::URLRequest> request(url_request_context_->CreateRequest(
-      GURL(kTestUrl), net::DEFAULT_PRIORITY, test_delegate_.get()));
-
-  // Set range header.
-  request->SetExtraRequestHeaderByName(
-      "Range", "bytes=3-5", false /* overwrite */);
-  request->Start();
-
-  base::RunLoop().Run();
-
-  EXPECT_EQ(net::OK, test_delegate_->request_status());
-
-  EXPECT_EQ(base::StringPiece(kExpectedFileContents).substr(3, 3),
-            test_delegate_->data_received());
-}
-
-TEST_F(ExternalFileURLRequestJobTest, WrongRangeHeader) {
-  std::unique_ptr<net::URLRequest> request(url_request_context_->CreateRequest(
-      GURL(kTestUrl), net::DEFAULT_PRIORITY, test_delegate_.get()));
-
-  // Set range header.
-  request->SetExtraRequestHeaderByName(
-      "Range", "Wrong Range Header Value", false /* overwrite */);
-  request->Start();
-
-  base::RunLoop().Run();
-
-  EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE,
-            test_delegate_->request_status());
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc
index 4fe9328..6774b343 100644
--- a/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc
@@ -477,7 +477,7 @@
 
 IN_PROC_BROWSER_TEST_F(AssistantOptInFlowTest, Basic) {
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      ash::mojom::VoiceInteractionState::STOPPED);
+      ash::mojom::AssistantState::READY);
 
   SetUpAssistantScreensForTest();
   assistant_optin_flow_screen_->Show();
@@ -513,7 +513,7 @@
 
 IN_PROC_BROWSER_TEST_F(AssistantOptInFlowTest, DisableScreenContext) {
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      ash::mojom::VoiceInteractionState::STOPPED);
+      ash::mojom::AssistantState::READY);
 
   SetUpAssistantScreensForTest();
   assistant_optin_flow_screen_->Show();
@@ -551,8 +551,7 @@
   EXPECT_FALSE(prefs->GetBoolean(assistant::prefs::kAssistantContextEnabled));
 }
 
-IN_PROC_BROWSER_TEST_F(AssistantOptInFlowTest,
-                       VoiceInteractionStateUpdateAfterShow) {
+IN_PROC_BROWSER_TEST_F(AssistantOptInFlowTest, AssistantStateUpdateAfterShow) {
   SetUpAssistantScreensForTest();
   assistant_optin_flow_screen_->Show();
 
@@ -567,7 +566,7 @@
   test::OobeJS().ExpectVisiblePath({"assistant-optin-flow-card", "loading"});
 
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      ash::mojom::VoiceInteractionState::STOPPED);
+      ash::mojom::AssistantState::READY);
 
   WaitForAssistantScreen("value-prop");
   TapWhenEnabled({"assistant-optin-flow-card", "value-prop", "next-button"});
@@ -598,7 +597,7 @@
   assistant_optin_flow_screen_->Show();
 
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      ash::mojom::VoiceInteractionState::STOPPED);
+      ash::mojom::AssistantState::READY);
 
   OobeScreenWaiter screen_waiter(AssistantOptInFlowScreenView::kScreenId);
   screen_waiter.set_assert_next_screen();
@@ -634,7 +633,7 @@
 IN_PROC_BROWSER_TEST_F(AssistantOptInFlowTest, RejectValueProp) {
   SetUpAssistantScreensForTest();
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      ash::mojom::VoiceInteractionState::STOPPED);
+      ash::mojom::AssistantState::READY);
 
   assistant_optin_flow_screen_->Show();
 
@@ -659,7 +658,7 @@
   assistant_settings_->set_consent_ui_flags(
       FakeAssistantSettings::CONSENT_UI_FLAG_ASK_EMAIL_OPT_IN);
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      ash::mojom::VoiceInteractionState::STOPPED);
+      ash::mojom::AssistantState::READY);
 
   SetUpAssistantScreensForTest();
   assistant_optin_flow_screen_->Show();
@@ -700,7 +699,7 @@
   assistant_settings_->set_consent_ui_flags(
       FakeAssistantSettings::CONSENT_UI_FLAG_ASK_EMAIL_OPT_IN);
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      ash::mojom::VoiceInteractionState::STOPPED);
+      ash::mojom::AssistantState::READY);
 
   SetUpAssistantScreensForTest();
   assistant_optin_flow_screen_->Show();
@@ -746,7 +745,7 @@
 
   SetUpAssistantScreensForTest();
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      ash::mojom::VoiceInteractionState::STOPPED);
+      ash::mojom::AssistantState::READY);
 
   assistant_optin_flow_screen_->Show();
 
@@ -781,7 +780,7 @@
 
   SetUpAssistantScreensForTest();
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      ash::mojom::VoiceInteractionState::STOPPED);
+      ash::mojom::AssistantState::READY);
 
   assistant_optin_flow_screen_->Show();
 
@@ -814,7 +813,7 @@
 
   SetUpAssistantScreensForTest();
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      ash::mojom::VoiceInteractionState::STOPPED);
+      ash::mojom::AssistantState::READY);
 
   assistant_optin_flow_screen_->Show();
 
@@ -904,7 +903,7 @@
 
   SetUpAssistantScreensForTest();
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      ash::mojom::VoiceInteractionState::STOPPED);
+      ash::mojom::AssistantState::READY);
 
   assistant_optin_flow_screen_->Show();
 
@@ -956,7 +955,7 @@
 
   SetUpAssistantScreensForTest();
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      ash::mojom::VoiceInteractionState::STOPPED);
+      ash::mojom::AssistantState::READY);
 
   assistant_optin_flow_screen_->Show();
 
@@ -1007,7 +1006,7 @@
       FakeAssistantSettings::CONSENT_UI_FLAG_WAA_DISABLED_BY_POLICY);
 
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      ash::mojom::VoiceInteractionState::STOPPED);
+      ash::mojom::AssistantState::READY);
   SetUpAssistantScreensForTest();
   assistant_optin_flow_screen_->Show();
 
@@ -1025,7 +1024,7 @@
       FakeAssistantSettings::CONSENT_UI_FLAG_ASSISTANT_DISABLED_BY_POLICY);
 
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      ash::mojom::VoiceInteractionState::STOPPED);
+      ash::mojom::AssistantState::READY);
   SetUpAssistantScreensForTest();
   assistant_optin_flow_screen_->Show();
 
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
index 5a4de3ea..87c13bf 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
@@ -25,51 +25,12 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_renderer_host.h"
-#include "net/base/request_priority.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using content::BrowserThread;
 
 namespace {
 
-// FakeURLRequestJobFactory returns NULL for all job creation requests and false
-// for all IsHandledProtocol() requests. FakeURLRequestJobFactory can be chained
-// to ProtocolHandlerRegistry::JobInterceptorFactory so the result of
-// MaybeCreateJobWithProtocolHandler() indicates whether the
-// ProtocolHandlerRegistry properly handled a job creation request.
-class FakeURLRequestJobFactory : public net::URLRequestJobFactory {
-  // net::URLRequestJobFactory implementation:
-  net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
-      const std::string& scheme,
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    return NULL;
-  }
-
-  net::URLRequestJob* MaybeInterceptRedirect(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate,
-      const GURL& location) const override {
-    return nullptr;
-  }
-
-  net::URLRequestJob* MaybeInterceptResponse(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    return nullptr;
-  }
-
-  bool IsHandledProtocol(const std::string& scheme) const override {
-    return false;
-  }
-  bool IsSafeRedirectTarget(const GURL& location) const override {
-    return true;
-  }
-};
-
 std::unique_ptr<base::DictionaryValue> GetProtocolHandlerValue(
     const std::string& protocol,
     const std::string& url) {
diff --git a/chrome/browser/download/download_history.cc b/chrome/browser/download/download_history.cc
index eb1d8f8..0b2a1e1 100644
--- a/chrome/browser/download/download_history.cc
+++ b/chrome/browser/download/download_history.cc
@@ -558,10 +558,6 @@
   }
 #endif
 
-  if (!base::FeatureList::IsEnabled(
-          download::features::kDownloadDBForNewDownloads)) {
-    return true;
-  }
   // When download DB is enabled, only downloads that are in terminal state
   // are added to or updated in history DB. Non-transient in-progress and
   // interrupted download will be stored in the in-progress DB.
diff --git a/chrome/browser/download/download_history_unittest.cc b/chrome/browser/download/download_history_unittest.cc
index 4898789e..ccce70df9 100644
--- a/chrome/browser/download/download_history_unittest.cc
+++ b/chrome/browser/download/download_history_unittest.cc
@@ -441,16 +441,6 @@
         .WillRepeatedly(SetArgPointee<0>(items));
   }
 
-  void SetDownloadDBEnabled(bool enabled) {
-    if (enabled) {
-      feature_list_.InitAndEnableFeature(
-          download::features::kDownloadDBForNewDownloads);
-    } else {
-      feature_list_.InitAndDisableFeature(
-          download::features::kDownloadDBForNewDownloads);
-    }
-  }
-
  private:
   content::BrowserTaskEnvironment task_environment_;
   std::vector<std::unique_ptr<StrictMockDownloadItem>> items_;
@@ -464,41 +454,9 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadHistoryTest);
 };
 
-// Test loading an item from the database, changing it, saving it back, removing
-// it.
-TEST_F(DownloadHistoryTest, DownloadHistoryTest_LoadWithoutDownloadDB) {
-  SetDownloadDBEnabled(false);
-
-  // Load a download from history, create the item, OnDownloadCreated,
-  // OnDownloadUpdated, OnDownloadRemoved.
-  history::DownloadRow row;
-  InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), "http://example.com/bar.pdf",
-                "http://example.com/referrer.html",
-                download::DownloadItem::IN_PROGRESS, &row);
-  {
-    std::vector<history::DownloadRow> rows = {row};
-    CreateDownloadHistory(std::move(rows));
-    ExpectNoDownloadCreated();
-  }
-  EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0)));
-
-  // Pretend that something changed on the item.
-  EXPECT_CALL(item(0), GetOpened()).WillRepeatedly(Return(true));
-  item(0).NotifyObserversDownloadUpdated();
-  row.opened = true;
-  ExpectDownloadUpdated(row, false);
-
-  // Pretend that the user removed the item.
-  IdSet ids;
-  ids.insert(row.id);
-  item(0).NotifyObserversDownloadRemoved();
-  ExpectDownloadsRemoved(ids);
-}
 
 // Test loading an item from the database, changing it and removing it.
 TEST_F(DownloadHistoryTest, DownloadHistoryTest_LoadWithDownloadDB) {
-  SetDownloadDBEnabled(true);
-
   // Load a download from history, create the item, OnDownloadCreated,
   // OnDownloadUpdated, OnDownloadRemoved.
   history::DownloadRow row;
@@ -573,12 +531,9 @@
   download_history()->RemoveObserver(&observer);
 }
 
-// Test creating an item, saving it to the database, changing it, saving it
-// back, removing it.
+// Test creating an completed item, saving it to the database, changing it,
+// saving it back, removing it.
 TEST_F(DownloadHistoryTest, DownloadHistoryTest_Create) {
-  // Disable download DB.
-  SetDownloadDBEnabled(false);
-
   // Create a fresh item not from history, OnDownloadCreated, OnDownloadUpdated,
   // OnDownloadRemoved.
   CreateDownloadHistory({});
@@ -586,7 +541,8 @@
   history::DownloadRow row;
   InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), "http://example.com/bar.pdf",
                 "http://example.com/referrer.html",
-                download::DownloadItem::IN_PROGRESS, &row);
+                download::DownloadItem::COMPLETE, &row);
+  EXPECT_CALL(item(0), IsDone()).WillRepeatedly(Return(true));
 
   // Pretend the manager just created |item|.
   CallOnDownloadCreated(0);
@@ -597,7 +553,9 @@
   EXPECT_CALL(item(0), GetOpened()).WillRepeatedly(Return(true));
   item(0).NotifyObserversDownloadUpdated();
   row.opened = true;
-  ExpectDownloadUpdated(row, false);
+  // The previous row was cached in memory, all the changes will be updated
+  // immediately
+  ExpectDownloadUpdated(row, true);
 
   // Pretend that the user removed the item.
   IdSet ids;
@@ -606,125 +564,11 @@
   ExpectDownloadsRemoved(ids);
 }
 
-// Test that changes to persisted fields in a DownloadItem triggers database
-// updates.
-TEST_F(DownloadHistoryTest, DownloadHistoryTest_Update) {
-  SetDownloadDBEnabled(false);
-  CreateDownloadHistory({});
-
-  history::DownloadRow row;
-  InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), "http://example.com/bar.pdf",
-                "http://example.com/referrer.html",
-                download::DownloadItem::IN_PROGRESS, &row);
-
-  CallOnDownloadCreated(0);
-  ExpectDownloadCreated(row);
-  EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0)));
-
-  base::FilePath new_path(FILE_PATH_LITERAL("/foo/baz.txt"));
-  base::Time new_time(base::Time::Now());
-  std::string new_etag("new etag");
-  std::string new_last_modifed("new last modified");
-
-  // current_path
-  EXPECT_CALL(item(0), GetFullPath()).WillRepeatedly(ReturnRefOfCopy(new_path));
-  row.current_path = new_path;
-  item(0).NotifyObserversDownloadUpdated();
-  ExpectDownloadUpdated(row, true);
-
-  // target_path
-  EXPECT_CALL(item(0), GetTargetFilePath())
-      .WillRepeatedly(ReturnRefOfCopy(new_path));
-  row.target_path = new_path;
-  item(0).NotifyObserversDownloadUpdated();
-  ExpectDownloadUpdated(row, false);
-
-  // end_time
-  EXPECT_CALL(item(0), GetEndTime()).WillRepeatedly(Return(new_time));
-  row.end_time = new_time;
-  item(0).NotifyObserversDownloadUpdated();
-  ExpectDownloadUpdated(row, false);
-
-  // received_bytes
-  EXPECT_CALL(item(0), GetReceivedBytes()).WillRepeatedly(Return(101));
-  row.received_bytes = 101;
-  item(0).NotifyObserversDownloadUpdated();
-  ExpectDownloadUpdated(row, false);
-
-  // received slices
-  std::vector<download::DownloadItem::ReceivedSlice> slices;
-  slices.push_back(download::DownloadItem::ReceivedSlice(0, 100));
-  slices.push_back(download::DownloadItem::ReceivedSlice(1000, 500));
-  EXPECT_CALL(item(0), GetReceivedSlices()).WillRepeatedly(
-      ReturnRefOfCopy(slices));
-  row.download_slice_info = history::GetHistoryDownloadSliceInfos(item(0));
-  item(0).NotifyObserversDownloadUpdated();
-  ExpectDownloadUpdated(row, false);
-
-  // total_bytes
-  EXPECT_CALL(item(0), GetTotalBytes()).WillRepeatedly(Return(102));
-  row.total_bytes = 102;
-  item(0).NotifyObserversDownloadUpdated();
-  ExpectDownloadUpdated(row, false);
-
-  // etag
-  EXPECT_CALL(item(0), GetETag()).WillRepeatedly(ReturnRefOfCopy(new_etag));
-  row.etag = new_etag;
-  item(0).NotifyObserversDownloadUpdated();
-  ExpectDownloadUpdated(row, false);
-
-  // last_modified
-  EXPECT_CALL(item(0), GetLastModifiedTime())
-      .WillRepeatedly(ReturnRefOfCopy(new_last_modifed));
-  row.last_modified = new_last_modifed;
-  item(0).NotifyObserversDownloadUpdated();
-  ExpectDownloadUpdated(row, false);
-
-  // state
-  // Changing the state to INTERRUPTED will remove its stored state.
-  EXPECT_CALL(item(0), GetState())
-      .WillRepeatedly(Return(download::DownloadItem::INTERRUPTED));
-  row.state = history::DownloadState::INTERRUPTED;
-  item(0).NotifyObserversDownloadUpdated();
-  ExpectDownloadUpdated(row, false);
-
-  // Changing the state back to IN_PROGRESS to reset its stored state.
-  EXPECT_CALL(item(0), GetState())
-      .WillRepeatedly(Return(download::DownloadItem::IN_PROGRESS));
-  row.state = history::DownloadState::IN_PROGRESS;
-  item(0).NotifyObserversDownloadUpdated();
-  ExpectDownloadUpdated(row, true);
-
-  // danger_type
-  EXPECT_CALL(item(0), GetDangerType())
-      .WillRepeatedly(Return(download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT));
-  row.danger_type = history::DownloadDangerType::DANGEROUS_CONTENT;
-  item(0).NotifyObserversDownloadUpdated();
-  ExpectDownloadUpdated(row, false);
-
-  // interrupt_reason
-  EXPECT_CALL(item(0), GetLastReason())
-      .WillRepeatedly(
-          Return(download::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED));
-  row.interrupt_reason = history::ToHistoryDownloadInterruptReason(
-      download::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED);
-  item(0).NotifyObserversDownloadUpdated();
-  ExpectDownloadUpdated(row, false);
-
-  // opened
-  EXPECT_CALL(item(0), GetOpened()).WillRepeatedly(Return(true));
-  row.opened = true;
-  item(0).NotifyObserversDownloadUpdated();
-  ExpectDownloadUpdated(row, false);
-}
-
 // Test creating a new item, saving it, removing it by setting it Temporary,
 // changing it without saving it back because it's Temporary, clearing
 // IsTemporary, saving it back, changing it, saving it back because it isn't
 // Temporary anymore.
 TEST_F(DownloadHistoryTest, DownloadHistoryTest_Temporary) {
-  SetDownloadDBEnabled(false);
-
   // Create a fresh item not from history, OnDownloadCreated, OnDownloadUpdated,
   // OnDownloadRemoved.
   CreateDownloadHistory({});
@@ -733,6 +577,7 @@
   InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), "http://example.com/bar.pdf",
                 "http://example.com/referrer.html",
                 download::DownloadItem::COMPLETE, &row);
+  EXPECT_CALL(item(0), IsDone()).WillRepeatedly(Return(true));
 
   // Pretend the manager just created |item|.
   CallOnDownloadCreated(0);
@@ -835,9 +680,6 @@
 
 // Test what happens when HistoryService/CreateDownload::CreateDownload() fails.
 TEST_F(DownloadHistoryTest, DownloadHistoryTest_CreateFailed) {
-  // Disable download DB.
-  SetDownloadDBEnabled(false);
-
   // Create a fresh item not from history, OnDownloadCreated, OnDownloadUpdated,
   // OnDownloadRemoved.
   CreateDownloadHistory({});
@@ -846,6 +688,7 @@
   InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), "http://example.com/bar.pdf",
                 "http://example.com/referrer.html",
                 download::DownloadItem::COMPLETE, &row);
+  EXPECT_CALL(item(0), IsDone()).WillRepeatedly(Return(true));
 
   FailCreateDownload();
   // Pretend the manager just created |item|.
@@ -892,11 +735,8 @@
   ExpectDownloadUpdated(row, true);
 }
 
-// Test creating and updating an item with DownloadDB enabled.
-TEST_F(DownloadHistoryTest, CreateWithDownloadDB) {
-  // Enable download DB.
-  SetDownloadDBEnabled(true);
-
+// Test creating and updating an completed item.
+TEST_F(DownloadHistoryTest, CreateCompletedItem) {
   // Create a fresh item not from download DB
   CreateDownloadHistory({});
 
@@ -920,9 +760,6 @@
 
 // Test creating history download item that exists in DownloadDB.
 TEST_F(DownloadHistoryTest, CreateHistoryItemInDownloadDB) {
-  // Enable download DB.
-  SetDownloadDBEnabled(true);
-
   history::DownloadRow row;
   InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), "http://example.com/bar.pdf",
                 "http://example.com/referrer.html",
@@ -950,18 +787,30 @@
   ExpectDownloadUpdated(row, true);
 }
 
-// Test creating a in-progress history download item that is non-resumable in
-// DownloadDB.
-TEST_F(DownloadHistoryTest,
-       CreateInProgressHistoryItemNonResumableInDownloadDB) {
-  // Enable download DB.
-  SetDownloadDBEnabled(true);
+// Test that new in-progress download will not be added to history.
+TEST_F(DownloadHistoryTest, CreateInProgressDownload) {
+  // Create an in-progress download.
+  CreateDownloadHistory({});
 
   history::DownloadRow row;
   InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), "http://example.com/bar.pdf",
                 "http://example.com/referrer.html",
                 download::DownloadItem::IN_PROGRESS, &row);
 
+  // Pretend the manager just created |item|.
+  CallOnDownloadCreated(0);
+  ExpectNoDownloadCreated();
+  EXPECT_FALSE(DownloadHistory::IsPersisted(&item(0)));
+}
+
+// Test that in-progress download already in history will be updated once it
+// becomes non-resumable.
+TEST_F(DownloadHistoryTest, InProgressHistoryItemBecomesNonResumable) {
+  history::DownloadRow row;
+  InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), "http://example.com/bar.pdf",
+                "http://example.com/referrer.html",
+                download::DownloadItem::IN_PROGRESS, &row);
+
   // Modify the item so it doesn't match the history record.
   EXPECT_CALL(item(0), GetLastReason())
       .WillRepeatedly(
@@ -981,9 +830,6 @@
 
 // Test loading history download item that will be cleared by |manager_|
 TEST_F(DownloadHistoryTest, RemoveClearedItemFromHistory) {
-  // Enable download DB.
-  SetDownloadDBEnabled(true);
-
   history::DownloadRow row;
   InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), "http://example.com/bar.pdf",
                 "http://example.com/referrer.html",
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
index e704227..7d6d747 100644
--- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
+++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
@@ -2798,6 +2798,110 @@
   EXPECT_EQ(first_tab_badge_text, action->GetDisplayBadgeText(first_tab_id));
 }
 
+// Ensure web request events are still dispatched even if DNR blocks/redirects
+// the request. (Regression test for crbug.com/999744).
+IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, WebRequestEvents) {
+  // Load the extension with a background script so scripts can be run from its
+  // generated background page.
+  set_has_background_script(true);
+
+  TestRule rule = CreateGenericRule();
+  rule.condition->url_filter = "||example.com";
+  rule.condition->resource_types = std::vector<std::string>({"main_frame"});
+  ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules(
+      {rule}, "test_extension", {URLPattern::kAllUrlsPattern}));
+
+  GURL url = embedded_test_server()->GetURL("example.com",
+                                            "/pages_with_script/index.html");
+
+  // Set up web request listeners listening to request to |url|.
+  const char kWebRequestListenerScript[] = R"(
+    let filter = {'urls' : ['%s'], 'types' : ['main_frame']};
+
+    let onBeforeRequestSeen = false;
+    chrome.webRequest.onBeforeRequest.addListener(() => {
+      onBeforeRequestSeen = true;
+    }, filter);
+
+    // The request will fail since it will be blocked by DNR.
+    chrome.webRequest.onErrorOccurred.addListener(() => {
+      if (onBeforeRequestSeen)
+        chrome.test.sendMessage('PASS');
+    }, filter);
+
+    chrome.test.sendMessage('INSTALLED');
+  )";
+
+  ExtensionTestMessageListener pass_listener("PASS", false /* will_reply */);
+  ExtensionTestMessageListener installed_listener("INSTALLED",
+                                                  false /* will_reply */);
+  ExecuteScriptInBackgroundPageNoWait(
+      last_loaded_extension_id(),
+      base::StringPrintf(kWebRequestListenerScript, url.spec().c_str()));
+
+  // Wait for the web request listeners to be installed before navigating.
+  ASSERT_TRUE(installed_listener.WaitUntilSatisfied());
+
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  ASSERT_FALSE(WasFrameWithScriptLoaded(GetMainFrame()));
+  EXPECT_TRUE(pass_listener.WaitUntilSatisfied());
+}
+
+// Ensure Declarative Net Request gets priority over the web request API.
+IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, WebRequestPriority) {
+  // Load the extension with a background script so scripts can be run from its
+  // generated background page.
+  set_has_background_script(true);
+
+  GURL url = embedded_test_server()->GetURL("example.com",
+                                            "/pages_with_script/index.html");
+  GURL redirect_url = embedded_test_server()->GetURL(
+      "redirect.com", "/pages_with_script/index.html");
+
+  TestRule example_com_redirect_rule = CreateGenericRule();
+  example_com_redirect_rule.condition->url_filter = "||example.com";
+  example_com_redirect_rule.condition->resource_types =
+      std::vector<std::string>({"main_frame"});
+  example_com_redirect_rule.action->type = std::string("redirect");
+  example_com_redirect_rule.action->redirect.emplace();
+  example_com_redirect_rule.action->redirect->url = redirect_url.spec();
+  example_com_redirect_rule.priority = kMinValidPriority;
+
+  ASSERT_NO_FATAL_FAILURE(
+      LoadExtensionWithRules({example_com_redirect_rule}, "test_extension",
+                             {URLPattern::kAllUrlsPattern}));
+
+  // Set up a web request listener to block the request to example.com.
+  const char kWebRequestBlockScript[] = R"(
+    let filter = {'urls' : ['%s'], 'types' : ['main_frame']};
+    chrome.webRequest.onBeforeRequest.addListener((details) => {
+      chrome.test.sendMessage('SEEN')
+    }, filter, ['blocking']);
+    chrome.test.sendMessage('INSTALLED');
+  )";
+
+  ExtensionTestMessageListener seen_listener("SEEN", false /* will_reply */);
+  ExtensionTestMessageListener installed_listener("INSTALLED",
+                                                  false /* will_reply */);
+  ExecuteScriptInBackgroundPageNoWait(
+      last_loaded_extension_id(),
+      base::StringPrintf(kWebRequestBlockScript, url.spec().c_str()));
+
+  // Wait for the web request listeners to be installed before navigating.
+  ASSERT_TRUE(installed_listener.WaitUntilSatisfied());
+
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  // Ensure the response from the web request listener was ignored and the
+  // request was redirected.
+  ASSERT_TRUE(WasFrameWithScriptLoaded(GetMainFrame()));
+  EXPECT_EQ(web_contents()->GetLastCommittedURL(), redirect_url);
+
+  // Ensure onBeforeRequest is seen by the web request extension.
+  EXPECT_TRUE(seen_listener.WaitUntilSatisfied());
+}
+
 // Test that the extension cannot retrieve the number of actions matched
 // from the badge text by calling chrome.browserAction.getBadgeText.
 IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest,
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
index 649e6cd1..e5d55f7 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -355,9 +355,8 @@
     if (flags & ui::TEXT_INPUT_FLAG_AUTOCAPITALIZE_WORDS)
       return input_method_private::AUTO_CAPITALIZE_TYPE_WORDS;
 
-    // At least one flag should be set. See |ComputeAutocapitalizeFlags| in
-    // third_party/blink/renderer/core/editing/ime/input_method_controller.cc
-    NOTREACHED();
+    // Autocapitalize flag may be missing for native text fields.
+    // See https://crbug.com/1002713.
     return input_method_private::AUTO_CAPITALIZE_TYPE_NONE;
   }
 
diff --git a/chrome/browser/lookalikes/safety_tips/reputation_service.cc b/chrome/browser/lookalikes/safety_tips/reputation_service.cc
index 7ba2c4b..0158cd4 100644
--- a/chrome/browser/lookalikes/safety_tips/reputation_service.cc
+++ b/chrome/browser/lookalikes/safety_tips/reputation_service.cc
@@ -139,8 +139,9 @@
   switch (type) {
     case FlaggedPage::FlagType::FlaggedPage_FlagType_UNKNOWN:
     case FlaggedPage::FlagType::FlaggedPage_FlagType_YOUNG_DOMAIN:
-      NOTREACHED();
-      break;
+      // Reached if component includes these flags, which might happen to
+      // support newer Chrome releases.
+      return security_state::SafetyTipStatus::kNone;
     case FlaggedPage::FlagType::FlaggedPage_FlagType_BAD_REP:
       return security_state::SafetyTipStatus::kBadReputation;
   }
@@ -264,8 +265,15 @@
           return a.pattern() < b.pattern();
         });
 
-    if (lower != flagged_pages.end() && pattern == lower->pattern()) {
-      return FlagTypeToSafetyTipStatus(lower->type());
+    while (lower != flagged_pages.end() && pattern == lower->pattern()) {
+      // Skip over sites with unexpected flag types and keep looking for other
+      // matches. This allows components to include flag types not handled by
+      // this release.
+      auto type = FlagTypeToSafetyTipStatus(lower->type());
+      if (type != security_state::SafetyTipStatus::kNone) {
+        return type;
+      }
+      ++lower;
     }
   }
 
diff --git a/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.cc b/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.cc
index e45f905..a5f1c41f 100644
--- a/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.cc
+++ b/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.cc
@@ -4,10 +4,11 @@
 
 #include "chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.h"
 
-#include "chrome/browser/lookalikes/safety_tips/safety_tips.pb.h"
 #include "chrome/browser/lookalikes/safety_tips/safety_tips_config.h"
 
-void SetSafetyTipBadRepPatterns(std::vector<std::string> patterns) {
+void SetSafetyTipPatternsWithFlagType(
+    std::vector<std::string> patterns,
+    chrome_browser_safety_tips::FlaggedPage::FlagType type) {
   std::unique_ptr<chrome_browser_safety_tips::SafetyTipsConfig> config_proto =
       std::make_unique<chrome_browser_safety_tips::SafetyTipsConfig>();
   // Any version ID will do.
@@ -17,8 +18,13 @@
     chrome_browser_safety_tips::FlaggedPage* page =
         config_proto->add_flagged_page();
     page->set_pattern(pattern);
-    page->set_type(chrome_browser_safety_tips::FlaggedPage::BAD_REP);
+    page->set_type(type);
   }
 
   safety_tips::SetRemoteConfigProto(std::move(config_proto));
 }
+
+void SetSafetyTipBadRepPatterns(std::vector<std::string> patterns) {
+  SetSafetyTipPatternsWithFlagType(
+      patterns, chrome_browser_safety_tips::FlaggedPage::BAD_REP);
+}
diff --git a/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.h b/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.h
index 769cc08b..59143634 100644
--- a/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.h
+++ b/chrome/browser/lookalikes/safety_tips/safety_tip_test_utils.h
@@ -7,7 +7,15 @@
 
 #include <string>
 
-// Sets the patterns to trigger a bad-reputation Safety Tip for tests.
+#include "chrome/browser/lookalikes/safety_tips/safety_tips.pb.h"
+
+// Sets the patterns included in component with the given flag type for tests.
+void SetSafetyTipPatternsWithFlagType(
+    std::vector<std::string> pattern,
+    chrome_browser_safety_tips::FlaggedPage::FlagType type);
+
+// Sets the patterns to trigger a bad-reputation Safety Tip for tests. This just
+// calls SetSafetyTipPatternsWithFlagType with BAD_REPUTATION as the type.
 void SetSafetyTipBadRepPatterns(std::vector<std::string> pattern);
 
 #endif  // CHROME_BROWSER_LOOKALIKES_SAFETY_TIPS_SAFETY_TIP_TEST_UTILS_H_
diff --git a/chrome/browser/media/cast_mirroring_service_host.cc b/chrome/browser/media/cast_mirroring_service_host.cc
index fc04e9e..58b1da08 100644
--- a/chrome/browser/media/cast_mirroring_service_host.cc
+++ b/chrome/browser/media/cast_mirroring_service_host.cc
@@ -273,7 +273,7 @@
 }
 
 void CastMirroringServiceHost::CreateAudioStream(
-    mojom::AudioStreamCreatorClientPtr client,
+    mojo::PendingRemote<mojom::AudioStreamCreatorClient> client,
     const media::AudioParameters& params,
     uint32_t total_segments) {
   content::WebContents* source_web_contents = nullptr;
@@ -292,27 +292,29 @@
   audio_stream_creator_->CreateLoopbackStream(
       source_web_contents, params, total_segments,
       base::BindRepeating(
-          [](mojom::AudioStreamCreatorClientPtr client,
+          [](mojo::PendingRemote<mojom::AudioStreamCreatorClient> client,
              media::mojom::AudioInputStreamPtr stream,
              media::mojom::AudioInputStreamClientRequest client_request,
              media::mojom::ReadOnlyAudioDataPipePtr data_pipe) {
             // TODO(xjz): Remove |initially_muted| argument from
             // mojom::AudioStreamCreatorClient::StreamCreated().
-            client->StreamCreated(std::move(stream), std::move(client_request),
-                                  std::move(data_pipe),
-                                  false /* initially_muted */);
+            mojo::Remote<mojom::AudioStreamCreatorClient> audio_client(
+                std::move(client));
+            audio_client->StreamCreated(
+                std::move(stream), std::move(client_request),
+                std::move(data_pipe), false /* initially_muted */);
           },
           base::Passed(&client)));
 }
 
 void CastMirroringServiceHost::ConnectToRemotingSource(
-    media::mojom::RemoterPtr remoter,
-    media::mojom::RemotingSourceRequest request) {
+    mojo::PendingRemote<media::mojom::Remoter> remoter,
+    mojo::PendingReceiver<media::mojom::RemotingSource> receiver) {
   if (source_media_id_.type == content::DesktopMediaID::TYPE_WEB_CONTENTS) {
     content::WebContents* source_contents = web_contents();
     if (source_contents) {
       CastRemotingConnector::Get(source_contents)
-          ->ConnectWithMediaRemoter(std::move(remoter), std::move(request));
+          ->ConnectWithMediaRemoter(std::move(remoter), std::move(receiver));
     }
   }
 }
diff --git a/chrome/browser/media/cast_mirroring_service_host.h b/chrome/browser/media/cast_mirroring_service_host.h
index b3db438..6e91bcc7 100644
--- a/chrome/browser/media/cast_mirroring_service_host.h
+++ b/chrome/browser/media/cast_mirroring_service_host.h
@@ -87,12 +87,13 @@
       media::mojom::VideoCaptureHostRequest request) override;
   void GetNetworkContext(
       mojo::PendingReceiver<network::mojom::NetworkContext> receiver) override;
-  void CreateAudioStream(mojom::AudioStreamCreatorClientPtr client,
-                         const media::AudioParameters& params,
-                         uint32_t total_segments) override;
+  void CreateAudioStream(
+      mojo::PendingRemote<mojom::AudioStreamCreatorClient> client,
+      const media::AudioParameters& params,
+      uint32_t total_segments) override;
   void ConnectToRemotingSource(
-      media::mojom::RemoterPtr remoter,
-      media::mojom::RemotingSourceRequest request) override;
+      mojo::PendingRemote<media::mojom::Remoter> remoter,
+      mojo::PendingReceiver<media::mojom::RemotingSource> receiver) override;
 
   // content::WebContentsObserver implementation.
   void WebContentsDestroyed() override;
diff --git a/chrome/browser/media/cast_mirroring_service_host_browsertest.cc b/chrome/browser/media/cast_mirroring_service_host_browsertest.cc
index 92c20cc..c9582812 100644
--- a/chrome/browser/media/cast_mirroring_service_host_browsertest.cc
+++ b/chrome/browser/media/cast_mirroring_service_host_browsertest.cc
@@ -128,9 +128,7 @@
       public mojom::AudioStreamCreatorClient {
  public:
   CastMirroringServiceHostBrowserTest()
-      : observer_binding_(this),
-        outbound_channel_binding_(this),
-        audio_client_binding_(this) {}
+      : observer_binding_(this), outbound_channel_binding_(this) {}
   ~CastMirroringServiceHostBrowserTest() override {}
 
  protected:
@@ -194,13 +192,11 @@
     media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
                                   media::CHANNEL_LAYOUT_STEREO, kAudioTimebase,
                                   kAudioTimebase / 100);
-    mojom::AudioStreamCreatorClientPtr audio_client_ptr;
-    audio_client_binding_.Bind(mojo::MakeRequest(&audio_client_ptr));
     base::RunLoop run_loop;
     EXPECT_CALL(*this, OnAudioStreamCreated())
         .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
-    host_->CreateAudioStream(std::move(audio_client_ptr), params,
-                             kTotalSegments);
+    host_->CreateAudioStream(audio_client_receiver_.BindNewPipeAndPassRemote(),
+                             params, kTotalSegments);
     run_loop.Run();
   }
 
@@ -232,7 +228,7 @@
 
   mojo::Binding<mojom::SessionObserver> observer_binding_;
   mojo::Binding<mojom::CastMessageChannel> outbound_channel_binding_;
-  mojo::Binding<mojom::AudioStreamCreatorClient> audio_client_binding_;
+  mojo::Receiver<mojom::AudioStreamCreatorClient> audio_client_receiver_{this};
   mojom::CastMessageChannelPtr inbound_channel_;
 
   std::unique_ptr<CastMirroringServiceHost> host_;
diff --git a/chrome/browser/media/cast_remoting_connector.cc b/chrome/browser/media/cast_remoting_connector.cc
index e65eaa9a..d7b55a2b 100644
--- a/chrome/browser/media/cast_remoting_connector.cc
+++ b/chrome/browser/media/cast_remoting_connector.cc
@@ -192,7 +192,6 @@
       permission_request_callback_(std::move(permission_request_callback)),
       active_bridge_(nullptr),
       deprecated_binding_(this),
-      binding_(this),
       pref_service_(pref_service) {
   DCHECK(permission_request_callback_);
 #if !defined(OS_ANDROID)
@@ -244,19 +243,18 @@
 }
 
 void CastRemotingConnector::ConnectWithMediaRemoter(
-    media::mojom::RemoterPtr remoter,
-    media::mojom::RemotingSourceRequest request) {
-  DCHECK(!binding_);
+    mojo::PendingRemote<media::mojom::Remoter> remoter,
+    mojo::PendingReceiver<media::mojom::RemotingSource> receiver) {
   DCHECK(!remoter_);
   DCHECK(remoter);
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DVLOG(2) << __func__;
 
-  binding_.Bind(std::move(request));
-  binding_.set_connection_error_handler(base::BindOnce(
+  receiver_.Bind(std::move(receiver));
+  receiver_.set_disconnect_handler(base::BindOnce(
       &CastRemotingConnector::OnMirrorServiceStopped, base::Unretained(this)));
-  remoter_ = std::move(remoter);
-  remoter_.set_connection_error_handler(base::BindOnce(
+  remoter_.Bind(std::move(remoter));
+  remoter_.set_disconnect_handler(base::BindOnce(
       &CastRemotingConnector::OnMirrorServiceStopped, base::Unretained(this)));
 }
 
@@ -267,8 +265,7 @@
   if (deprecated_binding_)
     deprecated_binding_.Close();
   deprecated_remoter_.reset();
-  if (binding_)
-    binding_.Close();
+  receiver_.reset();
   remoter_.reset();
 
   sink_metadata_ = RemotingSinkMetadata();
diff --git a/chrome/browser/media/cast_remoting_connector.h b/chrome/browser/media/cast_remoting_connector.h
index 30a16a2e..37e0482b 100644
--- a/chrome/browser/media/cast_remoting_connector.h
+++ b/chrome/browser/media/cast_remoting_connector.h
@@ -17,6 +17,8 @@
 #include "media/mojo/mojom/remoting.mojom.h"
 #include "media/mojo/mojom/remoting_common.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace content {
 class RenderFrameHost;
@@ -105,8 +107,9 @@
   void ResetRemotingPermission();
 
   // Used by Mirroring Service to connect the media remoter with this source.
-  void ConnectWithMediaRemoter(media::mojom::RemoterPtr remoter,
-                               media::mojom::RemotingSourceRequest request);
+  void ConnectWithMediaRemoter(
+      mojo::PendingRemote<media::mojom::Remoter> remoter,
+      mojo::PendingReceiver<media::mojom::RemotingSource> receiver);
 
  private:
   // Allow unit tests access to the private constructor and CreateBridge()
@@ -232,8 +235,8 @@
   mojo::Binding<media::mojom::MirrorServiceRemotingSource> deprecated_binding_;
   media::mojom::MirrorServiceRemoterPtr deprecated_remoter_;
 
-  mojo::Binding<media::mojom::RemotingSource> binding_;
-  media::mojom::RemoterPtr remoter_;
+  mojo::Receiver<media::mojom::RemotingSource> receiver_{this};
+  mojo::Remote<media::mojom::Remoter> remoter_;
 
   // Permission is checked the first time remoting requested to start for each
   // casting session.
diff --git a/chrome/browser/media/cast_remoting_connector_unittest.cc b/chrome/browser/media/cast_remoting_connector_unittest.cc
index 6d9ee7ed..9d9a0fb 100644
--- a/chrome/browser/media/cast_remoting_connector_unittest.cc
+++ b/chrome/browser/media/cast_remoting_connector_unittest.cc
@@ -103,11 +103,11 @@
 
 class MockRemotingSource : public media::mojom::RemotingSource {
  public:
-  MockRemotingSource() : binding_(this) {}
+  MockRemotingSource() {}
   ~MockRemotingSource() final {}
 
-  void Bind(RemotingSourceRequest request) {
-    binding_.Bind(std::move(request));
+  void Bind(mojo::PendingReceiver<RemotingSource> receiver) {
+    receiver_.Bind(std::move(receiver));
   }
 
   MOCK_METHOD0(OnSinkGone, void());
@@ -121,7 +121,7 @@
   }
 
  private:
-  mojo::Binding<media::mojom::RemotingSource> binding_;
+  mojo::Receiver<media::mojom::RemotingSource> receiver_{this};
 };
 
 // TODO(xjz): Remove the media::mojom::MirrorServiceRemoter implementation after
@@ -131,7 +131,7 @@
  public:
   // TODO(xjz): Remove this ctor after Mirroring Service is launched.
   explicit MockMediaRemoter(FakeMediaRouter* media_router)
-      : deprecated_binding_(this), binding_(this) {
+      : deprecated_binding_(this) {
     MirrorServiceRemoterPtr remoter;
     deprecated_binding_.Bind(mojo::MakeRequest(&remoter));
     media_router->OnMediaRemoterCreated(kRemotingTabId, std::move(remoter),
@@ -139,10 +139,8 @@
   }
 
   explicit MockMediaRemoter(CastRemotingConnector* connector)
-      : deprecated_binding_(this), binding_(this) {
-    RemoterPtr remoter;
-    binding_.Bind(mojo::MakeRequest(&remoter));
-    connector->ConnectWithMediaRemoter(std::move(remoter),
+      : deprecated_binding_(this) {
+    connector->ConnectWithMediaRemoter(receiver_.BindNewPipeAndPassRemote(),
                                        mojo::MakeRequest(&source_));
   }
 
@@ -220,7 +218,7 @@
   mojo::Binding<media::mojom::MirrorServiceRemoter> deprecated_binding_;
   MirrorServiceRemotingSourcePtr deprecated_source_;
 
-  mojo::Binding<media::mojom::Remoter> binding_;
+  mojo::Receiver<media::mojom::Remoter> receiver_{this};
   RemotingSourcePtr source_;
 };
 
diff --git a/chrome/browser/metrics/perf/perf_events_collector.cc b/chrome/browser/metrics/perf/perf_events_collector.cc
index b75b5fd..e7eae5b 100644
--- a/chrome/browser/metrics/perf/perf_events_collector.cc
+++ b/chrome/browser/metrics/perf/perf_events_collector.cc
@@ -254,6 +254,10 @@
 void PerfCollector::SetUp() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+  // Create DebugdClientProvider to bind its private DBus connection to the
+  // current sequence.
+  debugd_client_provider_ = std::make_unique<DebugdClientProvider>();
+
   auto task_runner = base::SequencedTaskRunnerHandle::Get();
   base::PostTask(
       FROM_HERE,
@@ -401,8 +405,10 @@
     base::TimeDelta duration,
     const std::vector<std::string>& perf_args,
     PerfOutputCall::DoneCallback callback) {
-  return std::make_unique<PerfOutputCall>(duration, perf_args,
-                                          std::move(callback));
+  DCHECK(debugd_client_provider_.get());
+  return std::make_unique<PerfOutputCall>(
+      debugd_client_provider_->debug_daemon_client(), duration, perf_args,
+      std::move(callback));
 }
 
 void PerfCollector::OnPerfOutputComplete(
diff --git a/chrome/browser/metrics/perf/perf_events_collector.h b/chrome/browser/metrics/perf/perf_events_collector.h
index 93f8721..9f13c2e 100644
--- a/chrome/browser/metrics/perf/perf_events_collector.h
+++ b/chrome/browser/metrics/perf/perf_events_collector.h
@@ -22,6 +22,7 @@
 namespace metrics {
 
 struct CPUIdentity;
+class DebugdClientProvider;
 class WindowedIncognitoObserver;
 
 // Enables collection of perf events profile data. perf aka "perf events" is a
@@ -110,6 +111,9 @@
   // Set of commands to choose from.
   RandomSelector command_selector_;
 
+  // |debugd_client_provider_| hosts the private DBus connection to debugd.
+  std::unique_ptr<DebugdClientProvider> debugd_client_provider_;
+
   // An active call to perf/quipper, if set.
   std::unique_ptr<PerfOutputCall> perf_output_call_;
 
diff --git a/chrome/browser/metrics/perf/perf_output.cc b/chrome/browser/metrics/perf/perf_output.cc
index 901c27c..de1bfe82 100644
--- a/chrome/browser/metrics/perf/perf_output.cc
+++ b/chrome/browser/metrics/perf/perf_output.cc
@@ -7,15 +7,44 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/task/post_task.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/debug_daemon_client.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "dbus/object_path.h"
+#include "dbus/object_proxy.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
 
 namespace metrics {
 
-PerfOutputCall::PerfOutputCall(base::TimeDelta duration,
+DebugdClientProvider::DebugdClientProvider()
+    : dbus_task_runner_(base::CreateSingleThreadTaskRunner(
+          {base::ThreadPool(), base::TaskPriority::BEST_EFFORT,
+           base::MayBlock()})),
+      debug_daemon_client_(chromeos::DebugDaemonClient::Create()) {
+  dbus::Bus::Options dbus_options;
+  dbus_options.bus_type = dbus::Bus::SYSTEM;
+  dbus_options.connection_type = dbus::Bus::PRIVATE;
+  dbus_options.dbus_task_runner = dbus_task_runner_;
+  dbus_bus_ = base::MakeRefCounted<dbus::Bus>(dbus_options);
+
+  debug_daemon_client_->Init(dbus_bus_.get());
+}
+
+DebugdClientProvider::~DebugdClientProvider() {
+  DCHECK(debug_daemon_client_);
+  DCHECK(dbus_bus_);
+
+  debug_daemon_client_ = nullptr;
+  dbus_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&dbus::Bus::ShutdownAndBlock, dbus_bus_));
+}
+
+PerfOutputCall::PerfOutputCall(chromeos::DebugDaemonClient* debug_daemon_client,
+                               base::TimeDelta duration,
                                const std::vector<std::string>& perf_args,
                                DoneCallback callback)
-    : duration_(duration),
+    : debug_daemon_client_(debug_daemon_client),
+      duration_(duration),
       perf_args_(perf_args),
       done_callback_(std::move(callback)),
       pending_stop_(false) {
@@ -30,14 +59,17 @@
   base::ScopedFD pipe_write_end =
       perf_data_pipe_reader_->StartIO(base::BindOnce(
           &PerfOutputCall::OnIOComplete, weak_factory_.GetWeakPtr()));
-  chromeos::DebugDaemonClient* client =
-      chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
-  client->GetPerfOutput(duration_, perf_args_, pipe_write_end.get(),
-                        base::BindOnce(&PerfOutputCall::OnGetPerfOutput,
-                                       weak_factory_.GetWeakPtr()));
+  DCHECK(debug_daemon_client_);
+  debug_daemon_client_->GetPerfOutput(
+      duration_, perf_args_, pipe_write_end.get(),
+      base::BindOnce(&PerfOutputCall::OnGetPerfOutput,
+                     weak_factory_.GetWeakPtr()));
 }
 
-PerfOutputCall::PerfOutputCall() : pending_stop_(false), weak_factory_(this) {}
+PerfOutputCall::PerfOutputCall()
+    : debug_daemon_client_(nullptr),
+      pending_stop_(false),
+      weak_factory_(this) {}
 
 PerfOutputCall::~PerfOutputCall() {}
 
@@ -86,9 +118,7 @@
 
 void PerfOutputCall::StopImpl() {
   DCHECK(perf_session_id_);
-  chromeos::DebugDaemonClient* client =
-      chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
-  client->StopPerf(*perf_session_id_, base::DoNothing());
+  debug_daemon_client_->StopPerf(*perf_session_id_, base::DoNothing());
 }
 
 }  // namespace metrics
diff --git a/chrome/browser/metrics/perf/perf_output.h b/chrome/browser/metrics/perf/perf_output.h
index 3ff51a3d..0d7a541 100644
--- a/chrome/browser/metrics/perf/perf_output.h
+++ b/chrome/browser/metrics/perf/perf_output.h
@@ -14,10 +14,39 @@
 #include "base/optional.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
+#include "chromeos/dbus/dbus_method_call_status.h"
 #include "chromeos/dbus/pipe_reader.h"
 
+namespace chromeos {
+class DebugDaemonClient;
+}  // namespace chromeos
+
+namespace dbus {
+class Bus;
+}  // namespace dbus
+
 namespace metrics {
 
+// This class hosts a private DBus connection for perf collection. The collector
+// sequence acts as the origin thread of the DBus Bus and ObjectProxy objects.
+class DebugdClientProvider {
+ public:
+  DebugdClientProvider();
+  ~DebugdClientProvider();
+
+  chromeos::DebugDaemonClient* debug_daemon_client() const {
+    return debug_daemon_client_.get();
+  }
+
+ private:
+  // The private bus.
+  scoped_refptr<dbus::Bus> dbus_bus_;
+  scoped_refptr<base::SequencedTaskRunner> dbus_task_runner_;
+  std::unique_ptr<chromeos::DebugDaemonClient> debug_daemon_client_;
+
+  DISALLOW_COPY_AND_ASSIGN(DebugdClientProvider);
+};
+
 // Class for handling getting output from perf over DBus. Manages the
 // asynchronous DBus call and retrieving data from quipper over a pipe.
 class PerfOutputCall {
@@ -31,7 +60,8 @@
   // The output is transferred to |perf_stdout|.
   using DoneCallback = base::OnceCallback<void(std::string perf_stdout)>;
 
-  PerfOutputCall(base::TimeDelta duration,
+  PerfOutputCall(chromeos::DebugDaemonClient* debug_daemon_client,
+                 base::TimeDelta duration,
                  const std::vector<std::string>& perf_args,
                  DoneCallback callback);
   virtual ~PerfOutputCall();
@@ -50,6 +80,9 @@
 
   void StopImpl();
 
+  // A non-retaining pointer to the DebugDaemonClient instance.
+  chromeos::DebugDaemonClient* debug_daemon_client_;
+
   // Used to capture perf data written to a pipe.
   std::unique_ptr<chromeos::PipeReader> perf_data_pipe_reader_;
 
diff --git a/chrome/browser/metrics/perf/perf_output_unittest.cc b/chrome/browser/metrics/perf/perf_output_unittest.cc
new file mode 100644
index 0000000..cf4012ba
--- /dev/null
+++ b/chrome/browser/metrics/perf/perf_output_unittest.cc
@@ -0,0 +1,194 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/metrics/perf/perf_output.h"
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "base/files/file.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/task/post_task.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread_restrictions.h"
+#include "chromeos/dbus/fake_debug_daemon_client.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/metrics_proto/sampled_profile.pb.h"
+
+namespace metrics {
+
+namespace {
+// Returns an example PerfDataProto. The contents don't have to make sense. They
+// just need to constitute a semantically valid protobuf.
+// |proto| is an output parameter that will contain the created protobuf.
+PerfDataProto GetExamplePerfDataProto() {
+  PerfDataProto proto;
+  proto.set_timestamp_sec(1435604013);  // Time since epoch in seconds.
+
+  PerfDataProto_PerfFileAttr* file_attr = proto.add_file_attrs();
+  file_attr->add_ids(61);
+  file_attr->add_ids(62);
+  file_attr->add_ids(63);
+
+  PerfDataProto_PerfEventAttr* attr = file_attr->mutable_attr();
+  attr->set_type(1);
+  attr->set_size(2);
+  attr->set_config(3);
+  attr->set_sample_period(4);
+  attr->set_sample_freq(5);
+
+  PerfDataProto_PerfEventStats* stats = proto.mutable_stats();
+  stats->set_num_events_read(100);
+  stats->set_num_sample_events(200);
+  stats->set_num_mmap_events(300);
+  stats->set_num_fork_events(400);
+  stats->set_num_exit_events(500);
+
+  return proto;
+}
+
+// Perf session ID returned by the GetPerfOutputFd DBus method call.
+const uint64_t kFakePerfSssionId = 101;
+// Profile collection duration is 4 seconds.
+const base::TimeDelta kProfileDuration = base::TimeDelta::FromSeconds(4);
+// Perf command line arguments.
+const std::vector<std::string> kPerfArgs{"perf",   "record", "-a", "-e",
+                                         "cycles", "-g",     "-c", "4000037"};
+
+// This fakes DebugDaemonClient by serving example perf data when the profiling
+// duration elapses.
+class FakeDebugDaemonClient : public chromeos::FakeDebugDaemonClient {
+ public:
+  FakeDebugDaemonClient()
+      : task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
+  ~FakeDebugDaemonClient() override {
+    EXPECT_FALSE(perf_output_file_.IsValid());
+  }
+
+  void GetPerfOutput(base::TimeDelta duration,
+                     const std::vector<std::string>& perf_args,
+                     int file_descriptor,
+                     chromeos::DBusMethodCallback<uint64_t> callback) override {
+    // We will write perf output to this pipe FD. dup() |file_descriptor|
+    // because it is closed after this method returns.
+    base::PlatformFile perf_output_fd = HANDLE_EINTR(dup(file_descriptor));
+    DCHECK_NE(perf_output_fd, -1);
+
+    perf_output_file_ = base::File(perf_output_fd, false);
+    EXPECT_TRUE(perf_output_file_.IsValid());
+
+    // Returns a fake perf session ID after calling GetPerfOutputFd.
+    task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(
+                       [](chromeos::DBusMethodCallback<uint64_t> callback) {
+                         std::move(callback).Run(kFakePerfSssionId);
+                       },
+                       std::move(callback)));
+  }
+
+  bool stop_called() const { return stop_called_; }
+
+  void StopPerf(uint64_t session_id,
+                chromeos::VoidDBusMethodCallback callback) override {
+    // Simulates stopping the perf session by writing perf data right away.
+    DCHECK(task_runner_->RunsTasksInCurrentSequence());
+    EXPECT_EQ(session_id, kFakePerfSssionId);
+    stop_called_ = true;
+    OnFakePerfOutputComplete();
+  }
+
+  // This simulates that profile collection is done and quipper writes perf data
+  // over the pipe.
+  void OnFakePerfOutputComplete() {
+    base::ScopedAllowBlockingForTesting allow_block;
+
+    auto perf_data = GetExamplePerfDataProto().SerializeAsString();
+    auto bytes_written = perf_output_file_.WriteAtCurrentPos(perf_data.c_str(),
+                                                             perf_data.size());
+    EXPECT_EQ(bytes_written, static_cast<ssize_t>(perf_data.size()));
+    // Need to close the pipe to unblock the pipe reader.
+    perf_output_file_.Close();
+  }
+
+ private:
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  base::File perf_output_file_;
+  chromeos::DBusMethodCallback<uint64_t> get_perf_outjput_callback_;
+  bool stop_called_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeDebugDaemonClient);
+};
+
+}  // namespace
+
+class PerfOutputCallTest : public testing::Test {
+ public:
+  PerfOutputCallTest() = default;
+
+  void SetUp() override {
+    debug_daemon_client_ = std::make_unique<FakeDebugDaemonClient>();
+  }
+
+  void TearDown() override { perf_output_call_.reset(); }
+
+  void OnPerfOutputComplete(std::string perf_output) {
+    perf_output_ = std::move(perf_output);
+  }
+
+ protected:
+  // |task_environment_| must be the first member (or at least before
+  // any member that cares about tasks) to be initialized first and
+  // destroyed last.
+  content::BrowserTaskEnvironment task_environment_;
+
+  std::unique_ptr<FakeDebugDaemonClient> debug_daemon_client_;
+  std::unique_ptr<PerfOutputCall> perf_output_call_;
+
+  std::string perf_output_;
+
+  DISALLOW_COPY_AND_ASSIGN(PerfOutputCallTest);
+};
+
+// Test getting perf output after profile duration elapses.
+TEST_F(PerfOutputCallTest, GetPerfOutput) {
+  perf_output_call_ = std::make_unique<PerfOutputCall>(
+      debug_daemon_client_.get(), kProfileDuration, kPerfArgs,
+      base::BindOnce(&PerfOutputCallTest::OnPerfOutputComplete,
+                     base::Unretained(this)));
+  // Not yet collected.
+  EXPECT_EQ(perf_output_, "");
+
+  // Perf data is available.
+  debug_daemon_client_->OnFakePerfOutputComplete();
+
+  // Note that we can call RunUntilIdle() only after fake perf data is written
+  // over the pipe, or RunUntilIdle() will block forever on the reading end.
+  task_environment_.RunUntilIdle();
+
+  EXPECT_FALSE(debug_daemon_client_->stop_called());
+  EXPECT_EQ(perf_output_, GetExamplePerfDataProto().SerializeAsString());
+}
+
+// Test stopping the perf session and get perf output right away.
+TEST_F(PerfOutputCallTest, Stop) {
+  perf_output_call_ = std::make_unique<PerfOutputCall>(
+      debug_daemon_client_.get(), kProfileDuration, kPerfArgs,
+      base::BindOnce(&PerfOutputCallTest::OnPerfOutputComplete,
+                     base::Unretained(this)));
+  // Not yet collected.
+  EXPECT_EQ(perf_output_, "");
+
+  // Perf data is available after calling Stop().
+  perf_output_call_->Stop();
+
+  // Note that we can call RunUntilIdle() only after fake perf data is written
+  // over the pipe, or RunUntilIdle() will block forever on the reading end.
+  task_environment_.RunUntilIdle();
+
+  EXPECT_TRUE(debug_daemon_client_->stop_called());
+  EXPECT_EQ(perf_output_, GetExamplePerfDataProto().SerializeAsString());
+}
+
+}  // namespace metrics
diff --git a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc
index ca26eae..16e8044 100644
--- a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc
+++ b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc
@@ -101,6 +101,7 @@
     if (!clients_.count(type) ||
         (notifications_.count(type) && notifications_[type].count(guid))) {
       // TODO(xingliu): Report duplicate guid failure.
+      std::move(callback).Run(false);
       return;
     }
 
@@ -109,6 +110,7 @@
     if (!valid) {
       stats::LogNotificationLifeCycleEvent(
           stats::NotificationLifeCycleEvent::kInvalidInput, type);
+      std::move(callback).Run(false);
       return;
     }
 
diff --git a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc
index 29c7a16..332e094 100644
--- a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc
+++ b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc
@@ -345,6 +345,43 @@
   EXPECT_EQ(buttons[1].type, ActionButtonType::kUnhelpful);
 }
 
+// Verifies that schedules a notification with unregistered client will fail.
+TEST_F(ScheduledNotificationManagerTest, ScheduleInvalidNotification) {
+  InitWithData(std::vector<NotificationEntry>());
+  NotificationData notification_data;
+  notification_data.title = base::UTF8ToUTF16(kTitle);
+  ScheduleParams schedule_params;
+  // Client type kTest3 is not registered.
+  auto params = std::make_unique<NotificationParams>(
+      SchedulerClientType::kTest3, notification_data, schedule_params);
+
+  EXPECT_CALL(*icon_store(), AddIcons(_, _)).Times(0);
+  EXPECT_CALL(*notification_store(), Add(_, _, _)).Times(0);
+  ScheduleNotification(std::move(params), false /*expected_success*/);
+}
+
+// Verifies that schedules a notification with duplicate guid will fail.
+TEST_F(ScheduledNotificationManagerTest, ScheduleNotificationDuplicateGuid) {
+  auto entry = CreateNotificationEntry(SchedulerClientType::kTest1);
+  entry.guid = kGuid;
+  InitWithData(std::vector<NotificationEntry>({entry}));
+
+  NotificationData notification_data;
+  notification_data.title = base::UTF8ToUTF16(kTitle);
+  ScheduleParams schedule_params;
+  auto params = std::make_unique<NotificationParams>(
+      SchedulerClientType::kTest1, notification_data, schedule_params);
+  params->schedule_params.deliver_time_start = base::Time::Now();
+  params->schedule_params.deliver_time_end =
+      base::Time::Now() + base::TimeDelta::FromDays(1);
+  // Duplicate guid.
+  params->guid = kGuid;
+
+  EXPECT_CALL(*icon_store(), AddIcons(_, _)).Times(0);
+  EXPECT_CALL(*notification_store(), Add(_, _, _)).Times(0);
+  ScheduleNotification(std::move(params), false /*expected_success*/);
+}
+
 // Test to schedule a notification without guid, we will auto generated one.
 TEST_F(ScheduledNotificationManagerTest, ScheduleNotificationEmptyGuid) {
   InitWithData(std::vector<NotificationEntry>());
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
index 6ace13b..e5118a0 100644
--- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
+++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
 #include "chrome/browser/page_load_metrics/page_load_tracker.h"
-#include "chrome/browser/prerender/prerender_contents.h"
 #include "components/page_load_metrics/common/page_load_timing.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/global_request_id.h"
@@ -95,9 +94,7 @@
       page_load_metrics_binding_(web_contents, this) {
   // Prerenders erroneously report that they are initially visible, so we
   // manually override visibility state for prerender.
-  const bool is_prerender =
-      prerender::PrerenderContents::FromWebContents(web_contents) != nullptr;
-  if (is_prerender)
+  if (embedder_interface_->IsPrerender(web_contents))
     in_foreground_ = false;
 
   RegisterInputEventObserver(web_contents->GetRenderViewHost());
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer_unittest.cc b/chrome/browser/page_load_metrics/metrics_web_contents_observer_unittest.cc
index e4b7d4b..dea94d9 100644
--- a/chrome/browser/page_load_metrics/metrics_web_contents_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer_unittest.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_tracker.h"
+#include "chrome/browser/prerender/prerender_contents.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/page_load_metrics/common/test/weak_mock_timer.h"
@@ -184,6 +185,9 @@
     SetMockTimer(timer->AsWeakPtr());
     return std::move(timer);
   }
+  bool IsPrerender(content::WebContents* web_contents) override {
+    return prerender::PrerenderContents::FromWebContents(web_contents);
+  }
   const std::vector<mojom::PageLoadTimingPtr>& updated_timings() const {
     return updated_timings_;
   }
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.cc b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.cc
index 5d9d825..d27b351 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.cc
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.cc
@@ -12,6 +12,7 @@
 #include "base/timer/timer.h"
 #include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.h"
+#include "chrome/browser/prerender/prerender_contents.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
 #include "content/public/browser/media_player_id.h"
 #include "content/public/browser/render_frame_host.h"
@@ -49,6 +50,10 @@
     return std::move(timer);
   }
 
+  bool IsPrerender(content::WebContents* web_contents) override {
+    return prerender::PrerenderContents::FromWebContents(web_contents);
+  }
+
  private:
   PageLoadMetricsObserverTester* test_;
 
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.h b/chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.h
index bafc09a..81238d6f 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.h
+++ b/chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.h
@@ -13,6 +13,10 @@
 class OneShotTimer;
 }  // namespace base
 
+namespace content {
+class WebContents;
+}  // namespace content
+
 namespace page_load_metrics {
 
 class PageLoadTracker;
@@ -25,6 +29,7 @@
   virtual bool IsNewTabPageUrl(const GURL& url) = 0;
   virtual void RegisterObservers(PageLoadTracker* metrics) = 0;
   virtual std::unique_ptr<base::OneShotTimer> CreateTimer() = 0;
+  virtual bool IsPrerender(content::WebContents* web_contents) = 0;
 };
 
 }  // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
index 0ad976f..614d616 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -72,6 +72,7 @@
   bool IsNewTabPageUrl(const GURL& url) override;
   void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override;
   std::unique_ptr<base::OneShotTimer> CreateTimer() override;
+  bool IsPrerender(content::WebContents* web_contents) override;
 
  private:
   bool IsPrerendering() const;
@@ -186,6 +187,10 @@
   return search::IsInstantNTPURL(url, profile);
 }
 
+bool PageLoadMetricsEmbedder::IsPrerender(content::WebContents* web_contents) {
+  return prerender::PrerenderContents::FromWebContents(web_contents);
+}
+
 }  // namespace
 
 void InitializePageLoadMetricsForWebContents(
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.cc b/chrome/browser/page_load_metrics/page_load_tracker.cc
index 27f19da1..37a651c 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.cc
+++ b/chrome/browser/page_load_metrics/page_load_tracker.cc
@@ -13,10 +13,8 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/time/default_tick_clock.h"
 #include "base/trace_event/trace_event.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
-#include "chrome/browser/prerender/prerender_contents.h"
 #include "components/page_load_metrics/common/page_load_timing.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_handle.h"
@@ -199,11 +197,8 @@
 
   UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadStartedInForeground,
                         started_in_foreground_);
-  const bool is_prerender = prerender::PrerenderContents::FromWebContents(
-                                navigation_handle->GetWebContents()) != nullptr;
-  if (is_prerender) {
+  if (embedder_interface_->IsPrerender(navigation_handle->GetWebContents()))
     UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadPrerender, true);
-  }
 }
 
 PageLoadTracker::~PageLoadTracker() {
diff --git a/chrome/browser/payments/payment_handler_enable_delegations_browsertest.cc b/chrome/browser/payments/payment_handler_enable_delegations_browsertest.cc
new file mode 100644
index 0000000..70fb38c
--- /dev/null
+++ b/chrome/browser/payments/payment_handler_enable_delegations_browsertest.cc
@@ -0,0 +1,81 @@
+// 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/macros.h"
+#include "build/build_config.h"
+#include "chrome/test/base/chrome_test_utils.h"
+#include "chrome/test/payments/payment_request_test_controller.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+#if defined(OS_ANDROID)
+#include "chrome/test/base/android/android_browser_test.h"
+#else
+#include "chrome/test/base/in_process_browser_test.h"
+#endif
+
+namespace payments {
+namespace {
+
+class PaymentHandlerEnableDelegationsTest : public PlatformBrowserTest {
+ public:
+  PaymentHandlerEnableDelegationsTest()
+      : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
+
+  ~PaymentHandlerEnableDelegationsTest() override {}
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitch(
+        switches::kEnableExperimentalWebPlatformFeatures);
+  }
+
+  void SetUpOnMainThread() override {
+    https_server_.ServeFilesFromSourceDirectory(
+        "components/test/data/payments");
+    ASSERT_TRUE(https_server_.Start());
+    ASSERT_TRUE(content::NavigateToURL(
+        GetActiveWebContents(), https_server_.GetURL("/payment_handler.html")));
+    test_controller_.SetUpOnMainThread();
+    PlatformBrowserTest::SetUpOnMainThread();
+  }
+
+  content::WebContents* GetActiveWebContents() {
+    return chrome_test_utils::GetActiveWebContents(this);
+  }
+
+ private:
+  PaymentRequestTestController test_controller_;
+  net::EmbeddedTestServer https_server_;
+
+  DISALLOW_COPY_AND_ASSIGN(PaymentHandlerEnableDelegationsTest);
+};
+
+IN_PROC_BROWSER_TEST_F(PaymentHandlerEnableDelegationsTest, EnableDelegations) {
+  std::string expected = "success";
+  EXPECT_EQ(expected, content::EvalJs(GetActiveWebContents(), "install()"));
+  EXPECT_EQ(
+      expected,
+      content::EvalJs(
+          GetActiveWebContents(),
+          "enableDelegations(["
+          "'shippingAddress', 'payerName', 'payerPhone', 'payerEmail'])"));
+}
+
+IN_PROC_BROWSER_TEST_F(PaymentHandlerEnableDelegationsTest,
+                       InvalidDelegations) {
+  std::string expected = "success";
+  EXPECT_EQ(expected, content::EvalJs(GetActiveWebContents(), "install()"));
+
+  expected =
+      "TypeError: Failed to execute 'enableDelegations' on 'PaymentManager': "
+      "The provided value 'invalid_delegation' is not a valid enum value of "
+      "type PaymentDelegation.";
+  EXPECT_EQ(expected,
+            content::EvalJs(GetActiveWebContents(),
+                            "enableDelegations(['invalid_delegation'])"));
+}
+
+}  // namespace
+}  // namespace payments
diff --git a/chrome/browser/popup_operations_interactive_uitest.cc b/chrome/browser/popup_operations_interactive_uitest.cc
index 8b58b0d3..4d65b058 100644
--- a/chrome/browser/popup_operations_interactive_uitest.cc
+++ b/chrome/browser/popup_operations_interactive_uitest.cc
@@ -109,7 +109,8 @@
 // OS_MACOSX: Missing automation provider support: http://crbug.com/1000752.
 #define MAYBE_OpenClosePopup DISABLED_OpenClosePopup
 #else
-#define MAYBE_OpenClosePopup OpenClosePopup
+// Temporary disabled due to flakiness: https://crbug.com/1002795.
+#define MAYBE_OpenClosePopup DISABLED_OpenClosePopup
 #endif
 
 // Clicking on a select element while another select element has its
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 33d88f92..6dec91d4 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -80,7 +80,6 @@
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
-#include "chrome/browser/chromeos/fileapi/external_file_protocol_handler.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/net/client_cert_filter_chromeos.h"
 #include "chrome/browser/chromeos/net/client_cert_store_chromeos.h"
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index 606892d..c1594b59 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -724,6 +724,8 @@
 
   renderTheme();
 
+  window.matchMedia('(prefers-color-scheme: dark)').onchange = onThemeChange;
+
   const searchboxApiHandle = embeddedSearchApiHandle.searchBox;
 
   if (configData.isGooglePage) {
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.js b/chrome/browser/resources/local_ntp/most_visited_single.js
index c497599..2ce41791 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -114,6 +114,12 @@
 const MD_MAX_NUM_CUSTOM_LINK_TILES = 10;
 
 /**
+ * Maximum number of tiles if Most Visited is enabled.
+ * @const {number}
+ */
+const MD_MAX_NUM_MOST_VISITED_TILES = 8;
+
+/**
  * Maximum number of tiles per row for Material Design.
  * @const {number}
  */
@@ -163,15 +169,6 @@
 let tiles = null;
 
 /**
- * Maximum number of MostVisited tiles to show at any time. If the host page
- * doesn't send enough tiles and custom links is not enabled, we fill them blank
- * tiles. This can be changed depending on what feature is enabled. Set by the
- * host page, while 8 is default.
- * @type {number}
- */
-let maxNumTiles = 8;
-
-/**
  * List of parameters passed by query args.
  * @type {Object}
  */
@@ -296,17 +293,13 @@
     this.tilesAlwaysVisible_ =
         params.tilesAlwaysVisible || MD_NUM_TILES_ALWAYS_VISIBLE;
     this.maxTilesPerRow_ = params.maxTilesPerRow || MD_MAX_TILES_PER_ROW;
-    this.maxTiles_ = params.maxTiles || maxNumTiles;
+    this.maxTiles_ = params.maxTiles || getMaxNumTiles();
 
     this.maxTilesPerRowWindow_ = this.getMaxTilesPerRow_();
 
     this.tiles_ =
         this.container_.getElementsByClassName(CLASSES.GRID_TILE_CONTAINER);
-    if (this.tiles_.length > this.maxTiles_) {
-      throw new Error(
-          'The number of tiles (' + this.tiles_.length +
-          ') exceeds the maximum (' + this.maxTiles_ + ').');
-    }
+    // Ignore any tiles past the maximum allowed.
     this.position_ = new Array(this.maxTiles_);
     this.order_ = new Array(this.maxTiles_);
     for (let i = 0; i < this.maxTiles_; i++) {
@@ -737,7 +730,7 @@
 
 /**
  * Log impression of an NTP tile.
- * @param {number} tileIndex Position of the tile, >= 0 and < |maxNumTiles|.
+ * @param {number} tileIndex Position of the tile, >= 0 and < getMaxNumTiles().
  * @param {number} tileTitleSource The source of the tile's title as received
  *     from getMostVisitedItemData.
  * @param {number} tileSource The tile's source as received from
@@ -754,7 +747,7 @@
 
 /**
  * Log click on an NTP tile.
- * @param {number} tileIndex Position of the tile, >= 0 and < |maxNumTiles|.
+ * @param {number} tileIndex Position of the tile, >= 0 and < getMaxNumTiles().
  * @param {number} tileTitleSource The source of the tile's title as received
  *     from getMostVisitedItemData.
  * @param {number} tileSource The tile's source as received from
@@ -771,6 +764,7 @@
 
 /**
  * Returns true if custom links are enabled.
+ * @return {boolean}
  */
 function isCustomLinksEnabled() {
   return customLinksFeatureEnabled &&
@@ -778,6 +772,16 @@
 }
 
 /**
+ * Returns the maximum number of tiles to show at any time. This can be changed
+ * depending on what feature is enabled.
+ * @return {number}
+ */
+function getMaxNumTiles() {
+  return isCustomLinksEnabled() ? MD_MAX_NUM_CUSTOM_LINK_TILES :
+                                  MD_MAX_NUM_MOST_VISITED_TILES;
+}
+
+/**
  * Down counts the DOM elements that we are waiting for the page to load.
  * When we get to 0, we send a message to the parent window.
  * This is usually used as an EventListener of onload/onerror.
@@ -905,7 +909,7 @@
 
   // Add an "add new custom link" button if we haven't reached the maximum
   // number of tiles.
-  if (isCustomLinksEnabled() && cur.childNodes.length < maxNumTiles) {
+  if (isCustomLinksEnabled() && cur.childNodes.length < getMaxNumTiles()) {
     const data = {
       'rid': -1,
       'title': queryArgs['addLink'],
@@ -989,27 +993,25 @@
 /**
  * Handler for the 'show' message from the host page, called when it wants to
  * add a suggestion tile.
- * It's also used to fill up our tiles to |maxNumTiles| if necessary.
  * @param {?MostVisitedData} args Data for the tile to be rendered.
  */
 function addTile(args) {
-  if (isFinite(args.rid)) {
-    // An actual suggestion. Grab the data from the embeddedSearch API.
-    const data =
-        chrome.embeddedSearch.newTabPage.getMostVisitedItemData(args.rid);
-    if (!data) {
-      return;
-    }
-
-    if (!data.faviconUrl) {
-      data.faviconUrl = 'chrome-search://favicon/size/16@' +
-          window.devicePixelRatio + 'x/' + data.renderViewId + '/' + data.rid;
-    }
-    tiles.appendChild(renderTile(data));
-  } else {
-    // An empty tile
-    tiles.appendChild(renderTile(null));
+  if (!isFinite(args.rid)) {
+    return;
   }
+
+  // Grab the tile's data from the embeddedSearch API.
+  const data =
+      chrome.embeddedSearch.newTabPage.getMostVisitedItemData(args.rid);
+  if (!data) {
+    return;
+  }
+
+  if (!data.faviconUrl) {
+    data.faviconUrl = 'chrome-search://favicon/size/16@' +
+        window.devicePixelRatio + 'x/' + data.renderViewId + '/' + data.rid;
+  }
+  tiles.appendChild(renderTile(data));
 }
 
 /**
@@ -1348,11 +1350,6 @@
     document.body.classList.add(CLASSES.GRID_LAYOUT);
   }
 
-  // Set the maximum number of tiles to show.
-  if (isCustomLinksEnabled()) {
-    maxNumTiles = MD_MAX_NUM_CUSTOM_LINK_TILES;
-  }
-
   currGrid = new Grid();
   // Set up layout updates on window resize. Throttled according to
   // |RESIZE_TIMEOUT_DELAY|.
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.html b/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.html
index d935ed6..22f80da 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.html
@@ -112,9 +112,12 @@
               <!-- Does not use <cr-link-row> due to custom aria label. -->
               <div id="profile-icon"
                   style="background-image: [[getIconImageSet_(
-                      profileIconUrl_)]]">
+                      profileIconUrl_)]]"
+                  on-click="onAccountManagerTap_"
+                  actionable$="[[isAccountManagerEnabled_]]">
               </div>
               <div class="middle two-line no-min-width"
+                  id="profile-row"
                   on-click="onAccountManagerTap_"
                   actionable$="[[isAccountManagerEnabled_]]">
                 <div class="flex text-elide settings-box-text">
diff --git a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js
index 559d651..c3bc1724 100644
--- a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js
+++ b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js
@@ -15,8 +15,8 @@
 /**
  * Indicates user's activity control consent status.
  *
- * Note: This should be kept in sync with ash::mojom::ConsentStatus in
- * ash/public/mojom/voice_interaction_controller.mojom
+ * Note: This should be kept in sync with ConsentStatus in
+ * chromeos/services/assistant/public/cpp/assistant_prefs.h
  * @enum {number}
  */
 const ConsentStatus = {
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index 327da536..71edbc8 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -161,12 +161,14 @@
           <div id="picture-subpage-trigger" class="settings-box first two-line">
             <template is="dom-if" if="[[syncStatus]]">
               <div id="profile-icon" on-click="onProfileTap_"
-                  actionable$="[[allowChangePicture_]]"
+                  actionable$="[[isProfileActionable_]]"
                   style="background-image: [[getIconImageSet_(
                       profileIconUrl_)]]">
               </div>
               <div class="middle two-line no-min-width"
-                  on-click="onProfileTap_" actionable>
+                  id="profile-row"
+                  on-click="onProfileTap_"
+                  actionable$="[[isProfileActionable_]]">
                 <div class="flex text-elide settings-box-text">
                   <span id="profile-name">[[profileName_]]</span>
                   <div class="secondary" hidden="[[!syncStatus.signedIn]]">
@@ -181,7 +183,7 @@
 <if expr="chromeos">
                 <cr-icon-button class="subpage-arrow"
                     id="profile-subpage-arrow"
-                    hidden="[[!allowChangePicture_]]"
+                    hidden="[[!isProfileActionable_]]"
                     aria-label="$i18n{changePictureTitle}"
                     aria-describedby="profile-name"></cr-icon-button>
 </if>
diff --git a/chrome/browser/resources/settings/people_page/people_page.js b/chrome/browser/resources/settings/people_page/people_page.js
index 988352af..8b3c821b 100644
--- a/chrome/browser/resources/settings/people_page/people_page.js
+++ b/chrome/browser/resources/settings/people_page/people_page.js
@@ -91,11 +91,11 @@
     profileIconUrl_: String,
 
     /**
-     * Whether clicking on the profile row should take the user to the
-     * "change picture" sub-page.
+     * Whether the profile row is clickable. The behavior depends on the
+     * platform.
      * @private
      */
-    allowChangePicture_: {
+    isProfileActionable_: {
       type: Boolean,
       value: function() {
         // On Chrome OS, only allow when SplitSettings is disabled.
@@ -379,8 +379,8 @@
   /** @private */
   onProfileTap_: function() {
     // <if expr="chromeos">
-    if (this.allowChangePicture_) {
-      // Testing allowChangePicture_ is simpler than conditionally removing
+    if (this.isProfileActionable_) {
+      // Testing isProfileActionable_ is simpler than conditionally removing
       // on-click handlers in the HTML.
       settings.navigateTo(settings.routes.CHANGE_PICTURE);
     }
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
index 30c4489..98b8abc 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -660,9 +660,6 @@
     sync_pb::GaiaPasswordReuse gaia_password_reuse_event;
     *gaia_password_reuse_event.mutable_reuse_lookup() = reuse_lookup;
 
-    WebUIInfoSingleton::GetInstance()->AddToSecurityEvents(
-        gaia_password_reuse_event);
-
     auto* identity_manager = IdentityManagerFactory::GetForProfileIfExists(
         profile_->GetOriginalProfile());
     if (identity_manager) {
@@ -671,6 +668,8 @@
       // SecurityEventRecorder only supports unconsented primary accounts.
       if (gaia::AreEmailsSame(unconsented_primary_account_info.email,
                               username_for_last_shown_warning())) {
+        WebUIInfoSingleton::GetInstance()->AddToSecurityEvents(
+            gaia_password_reuse_event);
         SecurityEventRecorderFactory::GetForProfile(profile_)
             ->RecordGaiaPasswordReuse(gaia_password_reuse_event);
       }
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
index 1b045e1..8e0bdd7 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -654,8 +654,6 @@
   // multiple prefs and doesn't add much verification value.
 }
 
-// TODO(crbug/914410): Renable once we know the SecurityEventRecorder won't
-// crash Chrome.
 TEST_F(ChromePasswordProtectionServiceTest,
        VerifyPasswordReuseDetectedSecurityEventRecorded) {
   identity_test_env()->SetPrimaryAccount(kTestEmail);
diff --git a/chrome/browser/ui/android/widget/BUILD.gn b/chrome/browser/ui/android/widget/BUILD.gn
index 13fa251..d9997707 100644
--- a/chrome/browser/ui/android/widget/BUILD.gn
+++ b/chrome/browser/ui/android/widget/BUILD.gn
@@ -6,11 +6,19 @@
 
 android_library("java") {
   java_files = [
+    "java/src/org/chromium/chrome/browser/ui/widget/AlwaysDismissedDialog.java",
+    "java/src/org/chromium/chrome/browser/ui/widget/BoundedLinearLayout.java",
     "java/src/org/chromium/chrome/browser/ui/widget/CompositeTouchDelegate.java",
+    "java/src/org/chromium/chrome/browser/ui/widget/DualControlLayout.java",
     "java/src/org/chromium/chrome/browser/ui/widget/FadingShadow.java",
     "java/src/org/chromium/chrome/browser/ui/widget/FadingShadowView.java",
+    "java/src/org/chromium/chrome/browser/ui/widget/FadingEdgeScrollView.java",
     "java/src/org/chromium/chrome/browser/ui/widget/ListMenuButton.java",
+    "java/src/org/chromium/chrome/browser/ui/widget/LoadingView.java",
+    "java/src/org/chromium/chrome/browser/ui/widget/text/AccessibleTextView.java",
+    "java/src/org/chromium/chrome/browser/ui/widget/text/AlertDialogEditText.java",
     "java/src/org/chromium/chrome/browser/ui/widget/text/TextViewWithCompoundDrawables.java",
+    "java/src/org/chromium/chrome/browser/ui/widget/text/VerticallyFixedEditText.java",
   ]
 
   deps = [
@@ -18,6 +26,7 @@
     "//base:base_java",
     "//third_party/android_deps:android_support_v7_appcompat_java",
     "//third_party/android_deps:com_android_support_design_java",
+    "//third_party/android_deps:com_android_support_interpolator_java",
     "//ui/android:ui_java",
   ]
 }
@@ -90,8 +99,35 @@
   ]
 }
 
+android_library("ui_widget_java_tests") {
+  testonly = true
+
+  java_files = [
+    "java/src/org/chromium/chrome/browser/ui/widget/DualControlLayoutTest.java",
+  ]
+  deps = [
+    ":java",
+    ":ui_widget_java_resources",
+    ":ui_widget_java_test_resources",
+    "//chrome/test/android:chrome_java_test_support",
+    "//third_party/android_support_test_runner:rules_java",
+    "//third_party/android_support_test_runner:runner_java",
+    "//third_party/junit",
+  ]
+}
+
+android_resources("ui_widget_java_test_resources") {
+  custom_package = "org.chromium.chrome.browser.ui.widget.test"
+  resource_dirs = [ "test/java/res" ]
+  deps = [
+    ":ui_widget_java_resources",
+    ":ui_widget_strings_grd",
+    "//ui/android:ui_java_resources",
+  ]
+}
+
 junit_binary("ui_widget_junit_tests") {
-  java_files = [ "junit/src/org/chromium/chrome//browser/ui/widget/CompositeTouchDelegateTest.java" ]
+  java_files = [ "java/src/org/chromium/chrome/browser/ui/widget/CompositeTouchDelegateUnitTest.java" ]
   deps = [
     ":java",
     "//base:base_java",
diff --git a/chrome/browser/ui/android/widget/DEPS b/chrome/browser/ui/android/widget/DEPS
index fa6e4ff..6abf63a 100644
--- a/chrome/browser/ui/android/widget/DEPS
+++ b/chrome/browser/ui/android/widget/DEPS
@@ -2,5 +2,6 @@
 
 include_rules = [
   "+base",
+  "+chrome/test/android",
   "+ui/android",
 ]
diff --git a/chrome/browser/ui/android/widget/java/res/values/attrs.xml b/chrome/browser/ui/android/widget/java/res/values/attrs.xml
index 91a500c..3e03a3da 100644
--- a/chrome/browser/ui/android/widget/java/res/values/attrs.xml
+++ b/chrome/browser/ui/android/widget/java/res/values/attrs.xml
@@ -4,6 +4,27 @@
      found in the LICENSE file. -->
 
 <resources>
+    <declare-styleable name="BoundedView">
+        <attr name="maxWidth" format="dimension" />
+        <attr name="maxWidthLandscape" format="dimension" />
+        <attr name="maxWidthPortrait" format="dimension" />
+        <attr name="maxHeight" format="dimension" />
+    </declare-styleable>
+
+    <declare-styleable name="DualControlLayout">
+        <attr name="stackedMargin" format="reference|dimension"/>
+        <attr name="primaryButtonText" format="reference|string"/>
+        <attr name="secondaryButtonText" format="reference|string"/>
+        <attr name="buttonAlignment" format="enum">
+            <enum name="start" value="0" />
+            <enum name="end" value="1" />
+            <enum name="apart" value="2" />
+        </attr>
+        <attr name="dualControlLayoutVerticalPadding" format="dimension"/>
+        <attr name="dualControlLayoutHorizontalPadding" format="dimension"/>
+    </declare-styleable>
+
+
     <declare-styleable name="ListMenuButton">
         <!-- Used to customize the width of the popup menu. -->
         <attr name="menuWidth" format="reference|dimension" />
diff --git a/chrome/browser/ui/android/widget/java/res/values/colors.xml b/chrome/browser/ui/android/widget/java/res/values/colors.xml
new file mode 100644
index 0000000..2a3b6bd9
--- /dev/null
+++ b/chrome/browser/ui/android/widget/java/res/values/colors.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<resources>
+    <color name="black_alpha_11">#1D000000</color>
+    <color name="toolbar_shadow_color">@color/black_alpha_11</color>
+</resources>
\ No newline at end of file
diff --git a/chrome/browser/ui/android/widget/java/res/values/dimens.xml b/chrome/browser/ui/android/widget/java/res/values/dimens.xml
index 275ee1e..43ef7fc 100644
--- a/chrome/browser/ui/android/widget/java/res/values/dimens.xml
+++ b/chrome/browser/ui/android/widget/java/res/values/dimens.xml
@@ -8,4 +8,7 @@
 
     <!-- Custom Menu dimensions -->
     <dimen name="menu_negative_software_vertical_offset">0dp</dimen>
+
+    <!-- DualControlLayout dimensions -->
+    <dimen name="dual_control_margin_between_items">8dp</dimen>
 </resources>
diff --git a/chrome/browser/ui/android/widget/java/res/values/ids.xml b/chrome/browser/ui/android/widget/java/res/values/ids.xml
new file mode 100644
index 0000000..36a598f0
--- /dev/null
+++ b/chrome/browser/ui/android/widget/java/res/values/ids.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- 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. -->
+
+<resources>
+    <!-- DualControlLayout button ids -->
+    <item type="id" name="button_primary" />
+    <item type="id" name="button_secondary" />
+</resources>
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/AlwaysDismissedDialog.java b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/AlwaysDismissedDialog.java
similarity index 96%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/AlwaysDismissedDialog.java
rename to chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/AlwaysDismissedDialog.java
index b1c9bd1..8825bd27 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/AlwaysDismissedDialog.java
+++ b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/AlwaysDismissedDialog.java
@@ -2,7 +2,7 @@
 // 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.widget;
+package org.chromium.chrome.browser.ui.widget;
 
 import android.app.Activity;
 import android.app.Dialog;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/BoundedLinearLayout.java b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/BoundedLinearLayout.java
similarity index 97%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/BoundedLinearLayout.java
rename to chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/BoundedLinearLayout.java
index 067aa87e..848c4b97 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/BoundedLinearLayout.java
+++ b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/BoundedLinearLayout.java
@@ -2,7 +2,7 @@
 // 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.widget;
+package org.chromium.chrome.browser.ui.widget;
 
 import android.content.Context;
 import android.content.res.TypedArray;
@@ -11,8 +11,6 @@
 import android.util.TypedValue;
 import android.widget.LinearLayout;
 
-import org.chromium.chrome.R;
-
 /**
  * A LinearLayout that can be constrained to a maximum size or percentage of the screen size.
  *
@@ -27,7 +25,6 @@
  *     ...
  */
 public class BoundedLinearLayout extends LinearLayout {
-
     private static final int NOT_SPECIFIED = -1;
 
     private TypedValue mMaxWidthLandscape = new TypedValue();
diff --git a/chrome/browser/ui/android/widget/junit/src/org/chromium/chrome/browser/ui/widget/CompositeTouchDelegateTest.java b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/CompositeTouchDelegateUnitTest.java
similarity index 97%
rename from chrome/browser/ui/android/widget/junit/src/org/chromium/chrome/browser/ui/widget/CompositeTouchDelegateTest.java
rename to chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/CompositeTouchDelegateUnitTest.java
index 29637ec..af40e4b 100644
--- a/chrome/browser/ui/android/widget/junit/src/org/chromium/chrome/browser/ui/widget/CompositeTouchDelegateTest.java
+++ b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/CompositeTouchDelegateUnitTest.java
@@ -24,7 +24,7 @@
  */
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
-public final class CompositeTouchDelegateTest {
+public final class CompositeTouchDelegateUnitTest {
     CompositeTouchDelegate mCompositeTouchDelegate;
 
     @Mock
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/DualControlLayout.java b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/DualControlLayout.java
similarity index 93%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/DualControlLayout.java
rename to chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/DualControlLayout.java
index da67141..6fcf798 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/DualControlLayout.java
+++ b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/DualControlLayout.java
@@ -2,7 +2,7 @@
 // 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.widget;
+package org.chromium.chrome.browser.ui.widget;
 
 import android.content.Context;
 import android.content.res.Resources;
@@ -15,7 +15,6 @@
 import android.widget.Button;
 
 import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.chrome.R;
 import org.chromium.ui.widget.ButtonCompat;
 
 import java.lang.annotation.Retention;
@@ -106,7 +105,7 @@
         // Cache dimensions.
         Resources resources = getContext().getResources();
         mHorizontalMarginBetweenViews =
-                resources.getDimensionPixelSize(R.dimen.infobar_control_margin_between_items);
+                resources.getDimensionPixelSize(R.dimen.dual_control_margin_between_items);
 
         if (attrs != null) parseAttributes(attrs);
     }
@@ -157,7 +156,8 @@
 
         // Measure the primary View, allowing it to be as wide as the Layout.
         int maxWidth = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED
-                ? Integer.MAX_VALUE : (MeasureSpec.getSize(widthMeasureSpec) - sidePadding);
+                ? Integer.MAX_VALUE
+                : (MeasureSpec.getSize(widthMeasureSpec) - sidePadding);
         int unspecifiedSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
         measureChild(mPrimaryView, unspecifiedSpec, unspecifiedSpec);
 
@@ -205,11 +205,11 @@
         boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
         boolean isPrimaryOnRight = (isRtl && mAlignment == DualControlLayoutAlignment.START)
                 || (!isRtl
-                           && (mAlignment == DualControlLayoutAlignment.APART
-                                      || mAlignment == DualControlLayoutAlignment.END));
+                        && (mAlignment == DualControlLayoutAlignment.APART
+                                || mAlignment == DualControlLayoutAlignment.END));
 
-        int primaryRight = isPrimaryOnRight
-                ? (width - rightPadding) : (mPrimaryView.getMeasuredWidth() + leftPadding);
+        int primaryRight = isPrimaryOnRight ? (width - rightPadding)
+                                            : (mPrimaryView.getMeasuredWidth() + leftPadding);
         int primaryLeft = primaryRight - mPrimaryView.getMeasuredWidth();
         int primaryTop = getPaddingTop();
         int primaryBottom = primaryTop + mPrimaryView.getMeasuredHeight();
@@ -234,7 +234,8 @@
             if (mAlignment == DualControlLayoutAlignment.APART) {
                 // Put the second View on the other side of the Layout from the primary View.
                 secondaryLeft = isPrimaryOnRight
-                        ? leftPadding : width - rightPadding - mSecondaryView.getMeasuredWidth();
+                        ? leftPadding
+                        : width - rightPadding - mSecondaryView.getMeasuredWidth();
                 secondaryRight = secondaryLeft + mSecondaryView.getMeasuredWidth();
             } else if (isPrimaryOnRight) {
                 // Sit to the left of the primary View.
@@ -252,8 +253,7 @@
                 secondaryRight = secondaryLeft + mSecondaryView.getMeasuredWidth();
             }
 
-            mSecondaryView.layout(
-                    secondaryLeft, secondaryTop, secondaryRight, secondaryBottom);
+            mSecondaryView.layout(secondaryLeft, secondaryTop, secondaryRight, secondaryBottom);
         }
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/DualControlLayoutTest.java b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/DualControlLayoutTest.java
similarity index 91%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/widget/DualControlLayoutTest.java
rename to chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/DualControlLayoutTest.java
index 14ae9a9..cf3e4e8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/DualControlLayoutTest.java
+++ b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/DualControlLayoutTest.java
@@ -2,7 +2,7 @@
 // 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.widget;
+package org.chromium.chrome.browser.ui.widget;
 
 import android.content.Context;
 import android.support.test.InstrumentationRegistry;
@@ -17,15 +17,16 @@
 import android.widget.FrameLayout;
 import android.widget.Space;
 
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.widget.DualControlLayout.DualControlLayoutAlignment;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.chrome.browser.ui.widget.DualControlLayout.DualControlLayoutAlignment;
+import org.chromium.chrome.browser.ui.widget.test.R;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+
 /**
  * Tests for DualControlLayout.
  */
@@ -50,7 +51,6 @@
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
-        mContext.setTheme(R.style.Theme_Chromium_WithWindowAnimation);
         mTinyControlWidth = INFOBAR_WIDTH / 4;
     }
 
@@ -122,10 +122,9 @@
         // Confirm that the primary View is in the correct place.
         if ((isRtl && alignment == DualControlLayoutAlignment.START)
                 || (!isRtl
-                           && (alignment == DualControlLayoutAlignment.APART
-                                      || alignment
-                                              == DualControlLayout.DualControlLayoutAlignment
-                                                         .END))) {
+                        && (alignment == DualControlLayoutAlignment.APART
+                                || alignment
+                                        == DualControlLayout.DualControlLayoutAlignment.END))) {
             int expectedRight = INFOBAR_WIDTH - (addPadding ? PADDING_RIGHT : 0);
             Assert.assertEquals(
                     "Primary should be on the right.", expectedRight, primary.getRight());
@@ -234,8 +233,7 @@
         layout.addView(secondary);
 
         // Trigger the measurement & layout algorithms.
-        int parentWidthSpec =
-                MeasureSpec.makeMeasureSpec(INFOBAR_WIDTH, MeasureSpec.AT_MOST);
+        int parentWidthSpec = MeasureSpec.makeMeasureSpec(INFOBAR_WIDTH, MeasureSpec.AT_MOST);
         int parentHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
         layout.measure(parentWidthSpec, parentHeightSpec);
         layout.layout(0, 0, layout.getMeasuredWidth(), layout.getMeasuredHeight());
@@ -280,24 +278,23 @@
         Assert.assertNull(layout.findViewById(R.id.button_primary));
         Assert.assertNull(layout.findViewById(R.id.button_secondary));
 
+        float dpToPx = mContext.getResources().getDisplayMetrics().density;
         // Inflate a DualControlLayout that has all of the attributes set and confirm they're used
         // correctly.
         FrameLayout containerView = new FrameLayout(mContext);
         LayoutInflater.from(mContext).inflate(
-                R.layout.autofill_editor_base_buttons, containerView, true);
-        DualControlLayout inflatedLayout =
-                (DualControlLayout) containerView.findViewById(R.id.button_bar);
+                R.layout.dual_control_test_layout, containerView, true);
+        DualControlLayout inflatedLayout = containerView.findViewById(R.id.button_bar);
         Assert.assertEquals(DualControlLayoutAlignment.END, inflatedLayout.getAlignment());
-        Assert.assertEquals(mContext.getResources().getDimensionPixelSize(
-                                    R.dimen.infobar_margin_between_stacked_buttons),
-                inflatedLayout.getStackedMargin());
+        Assert.assertEquals("Incorrect stacked margin. Should be 24dp", 24 * dpToPx,
+                inflatedLayout.getStackedMargin(), 0.f);
 
-        Button primaryButton = (Button) inflatedLayout.findViewById(R.id.button_primary);
+        Button primaryButton = inflatedLayout.findViewById(R.id.button_primary);
         Assert.assertNotNull(primaryButton);
-        Assert.assertEquals(mContext.getString(R.string.done), primaryButton.getText());
+        Assert.assertEquals("Done", primaryButton.getText());
 
         Button secondaryButton = (Button) inflatedLayout.findViewById(R.id.button_secondary);
         Assert.assertNotNull(secondaryButton);
-        Assert.assertEquals(mContext.getString(R.string.cancel), secondaryButton.getText());
+        Assert.assertEquals("Cancel", secondaryButton.getText());
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingEdgeScrollView.java b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/FadingEdgeScrollView.java
similarity index 97%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/FadingEdgeScrollView.java
rename to chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/FadingEdgeScrollView.java
index 7a145f84..dccf40e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingEdgeScrollView.java
+++ b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/FadingEdgeScrollView.java
@@ -2,7 +2,7 @@
 // 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.widget;
+package org.chromium.chrome.browser.ui.widget;
 
 import android.content.Context;
 import android.graphics.Canvas;
@@ -13,7 +13,6 @@
 import android.widget.ScrollView;
 
 import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.chrome.R;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -52,7 +51,7 @@
 
         mSeparatorColor =
                 ApiCompatibilityUtils.getColor(getResources(), R.color.toolbar_shadow_color);
-        mSeparatorHeight = getResources().getDimensionPixelSize(R.dimen.separator_height);
+        mSeparatorHeight = getResources().getDimensionPixelSize(R.dimen.divider_height);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/LoadingView.java b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/LoadingView.java
similarity index 87%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/LoadingView.java
rename to chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/LoadingView.java
index 2da140e6..0f54642 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/LoadingView.java
+++ b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/LoadingView.java
@@ -2,7 +2,7 @@
 // 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.widget;
+package org.chromium.chrome.browser.ui.widget;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -45,7 +45,9 @@
     private final Runnable mDelayedHide = new Runnable() {
         @Override
         public void run() {
-            animate().alpha(0.0f).setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE)
+            animate()
+                    .alpha(0.0f)
+                    .setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE)
                     .setListener(new AnimatorListenerAdapter() {
                         @Override
                         public void onAnimationEnd(Animator animation) {
@@ -91,8 +93,10 @@
         mShouldShow = false;
 
         if (getVisibility() == VISIBLE) {
-            postDelayed(mDelayedHide, Math.max(0,
-                    mStartTime + MINIMUM_ANIMATION_SHOW_TIME_MS - SystemClock.elapsedRealtime()));
+            postDelayed(mDelayedHide,
+                    Math.max(0,
+                            mStartTime + MINIMUM_ANIMATION_SHOW_TIME_MS
+                                    - SystemClock.elapsedRealtime()));
         }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibleTextView.java b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/text/AccessibleTextView.java
similarity index 94%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibleTextView.java
rename to chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/text/AccessibleTextView.java
index e2b28fc..af2feb5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibleTextView.java
+++ b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/text/AccessibleTextView.java
@@ -2,7 +2,7 @@
 // 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.widget.accessibility;
+package org.chromium.chrome.browser.ui.widget.text;
 
 import android.content.Context;
 import android.view.accessibility.AccessibilityEvent;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/AlertDialogEditText.java b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/text/AlertDialogEditText.java
similarity index 95%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/AlertDialogEditText.java
rename to chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/text/AlertDialogEditText.java
index b73b2b9..e1bedc6c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/AlertDialogEditText.java
+++ b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/text/AlertDialogEditText.java
@@ -2,7 +2,7 @@
 // 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.widget;
+package org.chromium.chrome.browser.ui.widget.text;
 
 import android.content.Context;
 import android.graphics.PorterDuff;
@@ -16,7 +16,7 @@
 import android.widget.EditText;
 
 import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ui.widget.R;
 
 /**
  * EditText to use in AlertDialog needed due to b/20882793 and b/122113958. This class should be
@@ -28,7 +28,6 @@
  * the change.
  */
 public class AlertDialogEditText extends AppCompatEditText {
-
     public AlertDialogEditText(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/VerticallyFixedEditText.java b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/text/VerticallyFixedEditText.java
similarity index 95%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/VerticallyFixedEditText.java
rename to chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/text/VerticallyFixedEditText.java
index 14cf919..82a2d84 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/VerticallyFixedEditText.java
+++ b/chrome/browser/ui/android/widget/java/src/org/chromium/chrome/browser/ui/widget/text/VerticallyFixedEditText.java
@@ -2,7 +2,7 @@
 // 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.widget;
+package org.chromium.chrome.browser.ui.widget.text;
 
 import android.content.Context;
 import android.support.v7.widget.AppCompatEditText;
@@ -14,7 +14,6 @@
  * can be useful when the EditText is put into a layout where it is smaller than it's normal height.
  */
 public class VerticallyFixedEditText extends AppCompatEditText {
-
     public VerticallyFixedEditText(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -37,5 +36,4 @@
         // TextView.bringPointIntoView(...) to change the vertical scroll.
         super.scrollTo(x, mBringingPointIntoView ? y : getScrollY());
     }
-
 }
diff --git a/chrome/browser/ui/android/widget/test/java/res/layout/dual_control_test_layout.xml b/chrome/browser/ui/android/widget/test/java/res/layout/dual_control_test_layout.xml
new file mode 100644
index 0000000..85410014
--- /dev/null
+++ b/chrome/browser/ui/android/widget/test/java/res/layout/dual_control_test_layout.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<org.chromium.chrome.browser.ui.widget.DualControlLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/button_bar"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp"
+    android:paddingTop="10dp"
+    android:paddingBottom="10dp"
+    app:stackedMargin="24dp"
+    app:primaryButtonText="Done"
+    app:secondaryButtonText="Cancel"
+    app:buttonAlignment="end" />
+
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder.cc b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder.cc
index 04db07f..07f8656 100644
--- a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder.cc
+++ b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder.cc
@@ -12,6 +12,23 @@
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
+namespace {
+
+bool ShouldShowInLauncher(const apps::AppUpdate& update) {
+  apps::mojom::Readiness readiness = update.Readiness();
+  switch (readiness) {
+    case apps::mojom::Readiness::kReady:
+    case apps::mojom::Readiness::kDisabledByUser:
+    case apps::mojom::Readiness::kDisabledByBlacklist:
+    case apps::mojom::Readiness::kTerminated:
+      return update.ShowInLauncher() == apps::mojom::OptionalBool::kTrue;
+    default:
+      return false;
+  }
+}
+
+}  // namespace
+
 // static
 apps::AppServiceProxy*
     AppServiceAppModelBuilder::app_service_proxy_for_testing_ = nullptr;
@@ -92,10 +109,7 @@
 
 void AppServiceAppModelBuilder::OnAppUpdate(const apps::AppUpdate& update) {
   ChromeAppListItem* item = GetAppItem(update.AppId());
-  apps::mojom::Readiness readiness = update.Readiness();
-  bool show = (((readiness == apps::mojom::Readiness::kReady) ||
-                (readiness == apps::mojom::Readiness::kDisabledByUser)) &&
-               (update.ShowInLauncher() == apps::mojom::OptionalBool::kTrue));
+  bool show = ShouldShowInLauncher(update);
   if (item) {
     if (show) {
       DCHECK(item->GetItemType() == AppServiceAppItem::kItemType);
diff --git a/chrome/browser/ui/ash/assistant/assistant_client.cc b/chrome/browser/ui/ash/assistant/assistant_client.cc
index b8b191e2..c891a65f 100644
--- a/chrome/browser/ui/ash/assistant/assistant_client.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_client.cc
@@ -8,7 +8,6 @@
 
 #include "ash/public/cpp/assistant/assistant_interface_binder.h"
 #include "ash/public/cpp/network_config_service.h"
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
 #include "chrome/browser/chromeos/arc/voice_interaction/voice_interaction_controller_client.h"
 #include "chrome/browser/chromeos/assistant/assistant_util.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -128,8 +127,8 @@
   // |STOPPED| and |NOT_READY|. |RUNNING| maps to UI is shown and an assistant
   // session is running.
   arc::VoiceInteractionControllerClient::Get()->NotifyStatusChanged(
-      running ? ash::mojom::VoiceInteractionState::STOPPED
-              : ash::mojom::VoiceInteractionState::NOT_READY);
+      running ? ash::mojom::AssistantState::READY
+              : ash::mojom::AssistantState::NOT_READY);
 }
 
 void AssistantClient::RequestAssistantStructure(
diff --git a/chrome/browser/ui/ash/assistant/assistant_setup.cc b/chrome/browser/ui/ash/assistant/assistant_setup.cc
index 7f1b828..51fa1f0 100644
--- a/chrome/browser/ui/ash/assistant/assistant_setup.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_setup.cc
@@ -42,8 +42,8 @@
   return chromeos::AssistantOptInDialog::BounceIfActive();
 }
 
-void AssistantSetup::OnStateChanged(ash::mojom::VoiceInteractionState state) {
-  if (state == ash::mojom::VoiceInteractionState::NOT_READY)
+void AssistantSetup::OnStateChanged(ash::mojom::AssistantState state) {
+  if (state == ash::mojom::AssistantState::NOT_READY)
     return;
 
   // Sync settings state when Assistant service started.
diff --git a/chrome/browser/ui/ash/assistant/assistant_setup.h b/chrome/browser/ui/ash/assistant/assistant_setup.h
index bb9dc7e..c8b42b9 100644
--- a/chrome/browser/ui/ash/assistant/assistant_setup.h
+++ b/chrome/browser/ui/ash/assistant/assistant_setup.h
@@ -32,7 +32,7 @@
 
  private:
   // arc::VoiceInteractionControllerClient::Observer overrides
-  void OnStateChanged(ash::mojom::VoiceInteractionState state) override;
+  void OnStateChanged(ash::mojom::AssistantState state) override;
 
   void SyncSettingsState();
   void OnGetSettingsResponse(const std::string& settings);
diff --git a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.cc b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.cc
index 2109d13..b4b6c1e 100644
--- a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.cc
+++ b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.cc
@@ -226,6 +226,13 @@
       active_controllable_session_ids_.size());
 }
 
+void MediaToolbarButtonController::OnDismissButtonClicked(
+    const std::string& id) {
+  auto it = sessions_.find(id);
+  if (it != sessions_.end())
+    it->second.item()->Dismiss();
+}
+
 void MediaToolbarButtonController::OnReceivedAudioFocusRequests(
     std::vector<media_session::mojom::AudioFocusRequestStatePtr> sessions) {
   for (auto& session : sessions)
diff --git a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h
index 03e6f971..98f5d0e 100644
--- a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h
+++ b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h
@@ -60,6 +60,9 @@
 
   void SetDialogDelegate(MediaDialogDelegate* delegate);
 
+  // Called when the dismiss button was clicked on a session.
+  void OnDismissButtonClicked(const std::string& id);
+
  private:
   friend class MediaToolbarButtonControllerTest;
 
diff --git a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller_unittest.cc b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller_unittest.cc
index 571d426b..95dbf0b 100644
--- a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller_unittest.cc
+++ b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller_unittest.cc
@@ -164,6 +164,10 @@
     item_itr->second.WebContentsDestroyed();
   }
 
+  void SimulateDismissButtonClicked(const base::UnguessableToken& id) {
+    controller_->OnDismissButtonClicked(id.ToString());
+  }
+
   void ExpectHistogramCountRecorded(int count, int size) {
     histogram_tester_.ExpectBucketCount(
         media_message_center::kCountHistogramName, count, size);
@@ -377,3 +381,20 @@
   SimulateTabClosed(id);
   testing::Mock::VerifyAndClearExpectations(&delegate());
 }
+
+TEST_F(MediaToolbarButtonControllerTest, DismissesMediaSession) {
+  // First, show the button.
+  EXPECT_CALL(delegate(), Show());
+  base::UnguessableToken id = SimulatePlayingControllableMedia();
+  testing::Mock::VerifyAndClearExpectations(&delegate());
+
+  // Then, open a dialog.
+  MockMediaDialogDelegate dialog_delegate;
+  EXPECT_CALL(dialog_delegate, ShowMediaSession(id.ToString(), _));
+  SimulateDialogOpened(&dialog_delegate);
+
+  // Then, click the dismiss button. This should stop and hide the session.
+  EXPECT_CALL(dialog_delegate, HideMediaSession(id.ToString()));
+  SimulateDismissButtonClicked(id);
+  testing::Mock::VerifyAndClearExpectations(&delegate());
+}
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
index 1398eac2..6d7a8f3 100644
--- a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
+++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
@@ -61,13 +61,18 @@
     const std::string& id,
     base::WeakPtr<media_message_center::MediaNotificationItem> item) {
   active_sessions_view_->ShowNotification(
-      id, std::make_unique<MediaNotificationContainerImpl>(this, item));
+      id, std::make_unique<MediaNotificationContainerImpl>(this, controller_,
+                                                           id, item));
   OnAnchorBoundsChanged();
 }
 
 void MediaDialogView::HideMediaSession(const std::string& id) {
   active_sessions_view_->HideNotification(id);
-  OnAnchorBoundsChanged();
+
+  if (active_sessions_view_->empty())
+    HideDialog();
+  else
+    OnAnchorBoundsChanged();
 }
 
 int MediaDialogView::GetDialogButtons() const {
diff --git a/chrome/browser/ui/views/global_media_controls/media_notification_container_impl.cc b/chrome/browser/ui/views/global_media_controls/media_notification_container_impl.cc
index e5247eb7..f41cc12c 100644
--- a/chrome/browser/ui/views/global_media_controls/media_notification_container_impl.cc
+++ b/chrome/browser/ui/views/global_media_controls/media_notification_container_impl.cc
@@ -4,7 +4,13 @@
 
 #include "chrome/browser/ui/views/global_media_controls/media_notification_container_impl.h"
 
+#include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h"
 #include "chrome/browser/ui/views/global_media_controls/media_dialog_view.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/vector_icons/vector_icons.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/button/image_button_factory.h"
 #include "ui/views/layout/fill_layout.h"
 
 namespace {
@@ -13,22 +19,41 @@
 constexpr int kWidth = 400;
 constexpr gfx::Size kNormalSize = gfx::Size(kWidth, 100);
 constexpr gfx::Size kExpandedSize = gfx::Size(kWidth, 150);
+constexpr gfx::Size kDismissButtonSize = gfx::Size(24, 24);
+constexpr int kDismissButtonIconSize = 20;
+constexpr SkColor kDefaultForegroundColor = SK_ColorBLACK;
 
 }  // anonymous namespace
 
 MediaNotificationContainerImpl::MediaNotificationContainerImpl(
     MediaDialogView* parent,
+    MediaToolbarButtonController* controller,
+    const std::string& id,
     base::WeakPtr<media_message_center::MediaNotificationItem> item)
-    : parent_(parent), view_(this, std::move(item), nullptr, base::string16()) {
+    : parent_(parent),
+      controller_(controller),
+      id_(id),
+      foreground_color_(kDefaultForegroundColor) {
   DCHECK(parent_);
+  DCHECK(controller_);
 
   SetLayoutManager(std::make_unique<views::FillLayout>());
 
   SetPreferredSize(kNormalSize);
 
-  view_.set_owned_by_client();
+  dismiss_button_ = views::CreateVectorImageButton(this);
+  dismiss_button_->SetPreferredSize(kDismissButtonSize);
+  dismiss_button_->SetTooltipText(l10n_util::GetStringUTF16(
+      IDS_GLOBAL_MEDIA_CONTROLS_DISMISS_ICON_TOOLTIP_TEXT));
+  dismiss_button_->set_owned_by_client();
+  dismiss_button_->SetVisible(false);
+  UpdateDismissButtonIcon();
 
-  AddChildView(&view_);
+  view_ = std::make_unique<media_message_center::MediaNotificationView>(
+      this, std::move(item), dismiss_button_.get(), base::string16());
+  view_->set_owned_by_client();
+
+  AddChildView(view_.get());
 }
 
 MediaNotificationContainerImpl::~MediaNotificationContainerImpl() = default;
@@ -38,3 +63,27 @@
   PreferredSizeChanged();
   parent_->OnAnchorBoundsChanged();
 }
+
+void MediaNotificationContainerImpl::OnMediaSessionInfoChanged(
+    const media_session::mojom::MediaSessionInfoPtr& session_info) {
+  dismiss_button_->SetVisible(
+      !session_info || session_info->playback_state !=
+                           media_session::mojom::MediaPlaybackState::kPlaying);
+}
+
+void MediaNotificationContainerImpl::OnForegoundColorChanged(SkColor color) {
+  foreground_color_ = color;
+  UpdateDismissButtonIcon();
+}
+
+void MediaNotificationContainerImpl::ButtonPressed(views::Button* sender,
+                                                   const ui::Event& event) {
+  DCHECK_EQ(dismiss_button_.get(), sender);
+  controller_->OnDismissButtonClicked(id_);
+}
+
+void MediaNotificationContainerImpl::UpdateDismissButtonIcon() {
+  views::SetImageFromVectorIcon(dismiss_button_.get(),
+                                vector_icons::kCloseRoundedIcon,
+                                kDismissButtonIconSize, foreground_color_);
+}
diff --git a/chrome/browser/ui/views/global_media_controls/media_notification_container_impl.h b/chrome/browser/ui/views/global_media_controls/media_notification_container_impl.h
index 4ba9ce3..527e83e4 100644
--- a/chrome/browser/ui/views/global_media_controls/media_notification_container_impl.h
+++ b/chrome/browser/ui/views/global_media_controls/media_notification_container_impl.h
@@ -5,35 +5,67 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_NOTIFICATION_CONTAINER_IMPL_H_
 #define CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_NOTIFICATION_CONTAINER_IMPL_H_
 
+#include <string>
+
 #include "base/memory/weak_ptr.h"
 #include "components/media_message_center/media_notification_container.h"
 #include "components/media_message_center/media_notification_view.h"
+#include "ui/views/controls/button/button.h"
 #include "ui/views/view.h"
 
 namespace media_message_center {
 class MediaNotificationItem;
 }  // namespace media_message_center
 
+namespace views {
+class ImageButton;
+}  // namespace views
+
 class MediaDialogView;
+class MediaToolbarButtonController;
 
 // MediaNotificationContainerImpl holds a media notification for display within
 // the MediaDialogView. The media notification shows metadata for a media
 // session and can control playback.
 class MediaNotificationContainerImpl
     : public views::View,
-      public media_message_center::MediaNotificationContainer {
+      public media_message_center::MediaNotificationContainer,
+      public views::ButtonListener {
  public:
-  explicit MediaNotificationContainerImpl(
+  MediaNotificationContainerImpl(
       MediaDialogView* parent,
+      MediaToolbarButtonController* controller,
+      const std::string& id,
       base::WeakPtr<media_message_center::MediaNotificationItem> item);
   ~MediaNotificationContainerImpl() override;
 
   // media_message_center::MediaNotificationContainer:
   void OnExpanded(bool expanded) override;
+  void OnMediaSessionInfoChanged(
+      const media_session::mojom::MediaSessionInfoPtr& session_info) override;
+  void OnForegoundColorChanged(SkColor color) override;
+
+  // views::ButtonListener:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
  private:
-  MediaDialogView* parent_;
-  media_message_center::MediaNotificationView view_;
+  void UpdateDismissButtonIcon();
+
+  // The MediaNotificationContainerImpl is owned by the
+  // MediaNotificationListView which is owned by the MediaDialogView, so the raw
+  // pointer is safe here.
+  MediaDialogView* const parent_;
+
+  // The MediaToolbarButtonController is owned by the MediaToolbarButton which
+  // outlives the MediaDialogView (and therefore the
+  // MediaNotificationContainerImpl).
+  MediaToolbarButtonController* const controller_;
+
+  const std::string id_;
+  std::unique_ptr<views::ImageButton> dismiss_button_;
+  std::unique_ptr<media_message_center::MediaNotificationView> view_;
+
+  SkColor foreground_color_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaNotificationContainerImpl);
 };
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
index 642411dfe..e9186d3 100644
--- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
@@ -563,3 +563,35 @@
     EXPECT_LE(kMinWarningTime.InMilliseconds(), samples.front().min);
   }
 }
+
+// Tests that Safety Tips aren't triggered on 'unknown' flag types from the
+// component updater. This permits us to add new flag types to the component
+// without breaking this release.
+IN_PROC_BROWSER_TEST_P(SafetyTipPageInfoBubbleViewBrowserTest,
+                       NotShownOnUnknownFlag) {
+  auto kNavigatedUrl = GetURL("site1.com");
+  SetSafetyTipPatternsWithFlagType(
+      {"site1.com/"}, chrome_browser_safety_tips::FlaggedPage::UNKNOWN);
+
+  SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement);
+  NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB);
+  EXPECT_FALSE(IsUIShowing());
+
+  ASSERT_NO_FATAL_FAILURE(CheckPageInfoDoesNotShowSafetyTipInfo(browser()));
+}
+
+// Tests that Safety Tips aren't triggered on domains flagged as 'YOUNG_DOMAIN'
+// in the component. This permits us to use this flag in the component without
+// breaking this release.
+IN_PROC_BROWSER_TEST_P(SafetyTipPageInfoBubbleViewBrowserTest,
+                       NotShownOnYoungDomain) {
+  auto kNavigatedUrl = GetURL("site1.com");
+  SetSafetyTipPatternsWithFlagType(
+      {"site1.com/"}, chrome_browser_safety_tips::FlaggedPage::YOUNG_DOMAIN);
+
+  SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement);
+  NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB);
+  EXPECT_FALSE(IsUIShowing());
+
+  ASSERT_NO_FATAL_FAILURE(CheckPageInfoDoesNotShowSafetyTipInfo(browser()));
+}
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
index 037e229..98baf3f2 100644
--- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -438,7 +438,7 @@
   layout->StartRow(views::GridLayout::kFixedSize, 0);
   layout->AddView(std::move(summary_row));
 
-  if (spec()->request_shipping()) {
+  if (state()->ShouldShowShippingSection()) {
     std::unique_ptr<PaymentRequestRowView> shipping_row = CreateShippingRow();
     shipping_row->set_previous_row(previous_row->AsWeakPtr());
     previous_row = shipping_row.get();
@@ -462,8 +462,7 @@
   previous_row = payment_method_row.get();
   layout->StartRow(views::GridLayout::kFixedSize, 0);
   layout->AddView(std::move(payment_method_row));
-  if (spec()->request_payer_name() || spec()->request_payer_email() ||
-      spec()->request_payer_phone()) {
+  if (state()->ShouldShowContactSection()) {
     std::unique_ptr<PaymentRequestRowView> contact_info_row =
         CreateContactInfoRow();
     contact_info_row->set_previous_row(previous_row->AsWeakPtr());
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller_browsertest.cc
index f302f2b..d58e737 100644
--- a/chrome/browser/ui/views/payments/payment_sheet_view_controller_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller_browsertest.cc
@@ -9,6 +9,7 @@
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/strings/grit/components_strings.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -153,6 +154,154 @@
   EXPECT_FALSE(IsPayButtonEnabled());
 }
 
+// Payment sheet view skips showing shipping section when the selected
+// instrument supports shipping delegation, the pay button is enabled with blank
+// autofill data.
+IN_PROC_BROWSER_TEST_F(PaymentSheetViewControllerContactDetailsTest,
+                       ShippingDelegation) {
+  // Install a payment handler which supports shipping delegation.
+  NavigateTo("/payment_handler.html");
+  std::string expected = "success";
+  EXPECT_EQ(expected, content::EvalJs(GetActiveWebContents(), "install()"));
+  EXPECT_EQ(expected,
+            content::EvalJs(GetActiveWebContents(),
+                            "enableDelegations(['shippingAddress'])"));
+  // Invoke a payment request with basic-card and methodName =
+  // window.location.origin + '/pay' supportedMethods (see payment_handler.js).
+  ResetEventWaiterForDialogOpened();
+  EXPECT_EQ(
+      expected,
+      content::EvalJs(GetActiveWebContents(),
+                      "paymentRequestWithOptions({requestShipping: true})"));
+  WaitForObservedEvent();
+
+  // Verify that no autofill profile exists.
+  EXPECT_TRUE(GetDataManager()->GetProfiles().empty());
+
+  // Shipping address and shipping option sections are not shown in the payment
+  // sheet view since handling shipping address is delegated to the selected
+  // payment handler (payment_handler.js).
+  EXPECT_EQ(nullptr,
+            dialog_view()->GetViewByID(static_cast<int>(
+                DialogViewID::PAYMENT_SHEET_SHIPPING_ADDRESS_SECTION_BUTTON)));
+  EXPECT_EQ(nullptr, dialog_view()->GetViewByID(static_cast<int>(
+                         DialogViewID::PAYMENT_SHEET_SHIPPING_OPTION_SECTION)));
+
+  // Payment button should be enabled with blank autofill profiles since the
+  // payment handler supports shipping delegation.
+  EXPECT_TRUE(IsPayButtonEnabled());
+}
+
+// Payment sheet view skips showing contact section when the selected instrument
+// supports contact delegation.
+IN_PROC_BROWSER_TEST_F(PaymentSheetViewControllerContactDetailsTest,
+                       ContactDelegation) {
+  // Install a payment handler which supports contact delegation.
+  NavigateTo("/payment_handler.html");
+  std::string expected = "success";
+  EXPECT_EQ(expected, content::EvalJs(GetActiveWebContents(), "install()"));
+  EXPECT_EQ(
+      expected,
+      content::EvalJs(
+          GetActiveWebContents(),
+          "enableDelegations(['payerName', 'payerPhone', 'payerEmail'])"));
+  // Invoke a payment request with basic-card and methodName =
+  // window.location.origin + '/pay' supportedMethods (see payment_handler.js).
+  ResetEventWaiterForDialogOpened();
+  EXPECT_EQ(
+      expected,
+      content::EvalJs(GetActiveWebContents(),
+                      "paymentRequestWithOptions({requestPayerName: true, "
+                      "requestPayerPhone: true, requestPayerEmail: true})"));
+  WaitForObservedEvent();
+
+  // Verify that no autofill profile exists.
+  EXPECT_TRUE(GetDataManager()->GetProfiles().empty());
+
+  // Contact info section is not shown in the payment sheet view since handling
+  // required contact information is delegated to the selected payment handler
+  // (payment_handler.js).
+  EXPECT_EQ(nullptr,
+            dialog_view()->GetViewByID(static_cast<int>(
+                DialogViewID::PAYMENT_SHEET_CONTACT_INFO_SECTION_BUTTON)));
+
+  // Payment button should be enabled with blank autofill profiles since the
+  // payment handler supports contact delegation.
+  EXPECT_TRUE(IsPayButtonEnabled());
+}
+
+// Payment sheet view shows shipping section when the selected instrument
+// supports contact delegation only.
+IN_PROC_BROWSER_TEST_F(PaymentSheetViewControllerContactDetailsTest,
+                       ContactOnlyDelegationShippingRequested) {
+  // Install a payment handler which supports contact delegation.
+  NavigateTo("/payment_handler.html");
+  std::string expected = "success";
+  EXPECT_EQ(expected, content::EvalJs(GetActiveWebContents(), "install()"));
+  EXPECT_EQ(
+      expected,
+      content::EvalJs(
+          GetActiveWebContents(),
+          "enableDelegations(['payerName', 'payerPhone', 'payerEmail'])"));
+  // Invoke a payment request with basic-card and methodName =
+  // window.location.origin + '/pay' supportedMethods (see payment_handler.js).
+  ResetEventWaiterForDialogOpened();
+  EXPECT_EQ(
+      expected,
+      content::EvalJs(GetActiveWebContents(),
+                      "paymentRequestWithOptions({requestShipping: true})"));
+  WaitForObservedEvent();
+
+  // Verify that no autofill profile exists.
+  EXPECT_TRUE(GetDataManager()->GetProfiles().empty());
+
+  // Shipping section is still shown since the selected payment instrument does
+  // not support delegation of shipping address.
+  EXPECT_NE(nullptr,
+            dialog_view()->GetViewByID(static_cast<int>(
+                DialogViewID::PAYMENT_SHEET_SHIPPING_ADDRESS_SECTION_BUTTON)));
+
+  // Payment button should be disabled since the browser should collect shipping
+  // address.
+  EXPECT_FALSE(IsPayButtonEnabled());
+}
+
+// Payment sheet view shows contact section when the selected instrument does
+// not support delegation of all required contact details.
+IN_PROC_BROWSER_TEST_F(PaymentSheetViewControllerContactDetailsTest,
+                       PartialContactDelegation) {
+  // Install a payment handler which supports delegation of all required contact
+  // information except payer's email.
+  NavigateTo("/payment_handler.html");
+  std::string expected = "success";
+  EXPECT_EQ(expected, content::EvalJs(GetActiveWebContents(), "install()"));
+  EXPECT_EQ(expected,
+            content::EvalJs(GetActiveWebContents(),
+                            "enableDelegations(['payerName', 'payerPhone'])"));
+  // Invoke a payment request with basic-card and methodName =
+  // window.location.origin + '/pay' supportedMethods (see payment_handler.js).
+  ResetEventWaiterForDialogOpened();
+  EXPECT_EQ(
+      expected,
+      content::EvalJs(GetActiveWebContents(),
+                      "paymentRequestWithOptions({requestPayerName: true, "
+                      "requestPayerPhone: true, requestPayerEmail: true})"));
+  WaitForObservedEvent();
+
+  // Verify that no autofill profile exists.
+  EXPECT_TRUE(GetDataManager()->GetProfiles().empty());
+
+  // Contact info section is still shown since the selected payment instrument
+  // does not support delegation of all required contact info.
+  EXPECT_NE(nullptr,
+            dialog_view()->GetViewByID(static_cast<int>(
+                DialogViewID::PAYMENT_SHEET_CONTACT_INFO_SECTION_BUTTON)));
+
+  // Payment button should be disabled since the browser should collect payer's
+  // email.
+  EXPECT_FALSE(IsPayButtonEnabled());
+}
+
 // If shipping and contact info are requested, show all the rows.
 IN_PROC_BROWSER_TEST_F(PaymentSheetViewControllerContactDetailsTest,
                        AllRowsPresent) {
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
index d640e0c9..35c327b 100644
--- a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
+++ b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
@@ -76,6 +76,7 @@
       profile_(profile)
 #if defined(OS_CHROMEOS)
       ,
+      arc_app_list_prefs_observer_(this),
       shelf_delegate_(this)
 #endif
 {
@@ -91,7 +92,7 @@
 
 #if defined(OS_CHROMEOS)
   if (arc::IsArcAllowedForProfile(profile_)) {
-    ArcAppListPrefs::Get(profile_)->AddObserver(this);
+    arc_app_list_prefs_observer_.Add(ArcAppListPrefs::Get(profile_));
   }
 #endif  // OS_CHROMEOS
 }
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler.h b/chrome/browser/ui/webui/app_management/app_management_page_handler.h
index 69ceb02..baeef29 100644
--- a/chrome/browser/ui/webui/app_management/app_management_page_handler.h
+++ b/chrome/browser/ui/webui/app_management/app_management_page_handler.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_WEBUI_APP_MANAGEMENT_APP_MANAGEMENT_PAGE_HANDLER_H_
 
 #include "base/macros.h"
+#include "base/scoped_observer.h"
 #include "chrome/browser/ui/webui/app_management/app_management.mojom.h"
 #include "chrome/browser/ui/webui/app_management/app_management_shelf_delegate_chromeos.h"
 #include "chrome/services/app_service/public/cpp/app_registry_cache.h"
@@ -74,6 +75,8 @@
   Profile* profile_;
 
 #if defined(OS_CHROMEOS)
+  ScopedObserver<ArcAppListPrefs, AppManagementPageHandler>
+      arc_app_list_prefs_observer_;
   AppManagementShelfDelegate shelf_delegate_;
 #endif  // OS_CHROMEOS
 
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
index aaf15c12..e91c9555 100644
--- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
@@ -8,7 +8,6 @@
 #include <string>
 #include <utility>
 
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/browser/ui/webui/chromeos/first_run/first_run_handler.cc b/chrome/browser/ui/webui/chromeos/first_run/first_run_handler.cc
index 46afde2..92020cd 100644
--- a/chrome/browser/ui/webui/chromeos/first_run/first_run_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/first_run/first_run_handler.cc
@@ -6,7 +6,6 @@
 
 #include <utility>
 
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
 #include "base/bind.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/assistant/assistant_util.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
index 57f70af..49242cca 100644
--- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
@@ -216,8 +216,8 @@
   // Make sure enable Assistant service since we need it during the flow.
   prefs->SetBoolean(chromeos::assistant::prefs::kAssistantEnabled, true);
 
-  if (arc::VoiceInteractionControllerClient::Get()->voice_interaction_state() ==
-      ash::mojom::VoiceInteractionState::NOT_READY) {
+  if (arc::VoiceInteractionControllerClient::Get()->assistant_state() ==
+      ash::mojom::AssistantState::NOT_READY) {
     arc::VoiceInteractionControllerClient::Get()->AddObserver(this);
   } else {
     BindAssistantSettingsManager();
@@ -271,8 +271,8 @@
 }
 
 void AssistantOptInFlowScreenHandler::OnStateChanged(
-    ash::mojom::VoiceInteractionState state) {
-  if (state != ash::mojom::VoiceInteractionState::NOT_READY) {
+    ash::mojom::AssistantState state) {
+  if (state != ash::mojom::AssistantState::NOT_READY) {
     BindAssistantSettingsManager();
     arc::VoiceInteractionControllerClient::Get()->RemoveObserver(this);
   }
diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h
index 9810c08..e595c46 100644
--- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h
@@ -94,7 +94,7 @@
   void Initialize() override;
 
   // arc::VoiceInteractionControllerClient::Observer overrides
-  void OnStateChanged(ash::mojom::VoiceInteractionState state) override;
+  void OnStateChanged(ash::mojom::AssistantState state) override;
 
   // Connect to assistant settings manager.
   void BindAssistantSettingsManager();
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 6df5175..025fd37 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -68,7 +68,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "ash/public/cpp/ash_switches.h"
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
+#include "ash/public/mojom/assistant_state_controller.mojom.h"
 #include "base/system/sys_info.h"
 #include "chrome/browser/chromeos/account_manager/account_manager_util.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
diff --git a/chrome/browser/vr/webxr_vr_input_browser_test.cc b/chrome/browser/vr/webxr_vr_input_browser_test.cc
index e99a9e8..b33ea5d 100644
--- a/chrome/browser/vr/webxr_vr_input_browser_test.cc
+++ b/chrome/browser/vr/webxr_vr_input_browser_test.cc
@@ -30,9 +30,9 @@
   // verified its size above, so we can check the expressions a single time
   // here instead of polling them.
   for (size_t i = 0; i < expected_values.size(); ++i) {
-    t->RunJavaScriptAndExtractBoolOrFail("isProfileEqualTo(" +
-                                         base::NumberToString(i) + ", '" +
-                                         expected_values[i] + "')");
+    ASSERT_TRUE(t->RunJavaScriptAndExtractBoolOrFail(
+        "isProfileEqualTo(" + base::NumberToString(i) + ", '" +
+        expected_values[i] + "')"));
   }
 }
 
@@ -593,12 +593,14 @@
     button_count = "4";
 
   // Make sure both gamepads have the expected button count and mapping.
-  t->RunJavaScriptAndExtractBoolOrFail("isButtonCountEqualTo(" + button_count +
-                                       ", 0)");
-  t->RunJavaScriptAndExtractBoolOrFail("isButtonCountEqualTo(" + button_count +
-                                       ", 1)");
-  t->RunJavaScriptAndExtractBoolOrFail("isMappingEqualTo('xr-standard', 0)");
-  t->RunJavaScriptAndExtractBoolOrFail("isMappingEqualTo('xr-standard', 1)");
+  ASSERT_TRUE(t->RunJavaScriptAndExtractBoolOrFail("isButtonCountEqualTo(" +
+                                                   button_count + ", 0)"));
+  ASSERT_TRUE(t->RunJavaScriptAndExtractBoolOrFail("isButtonCountEqualTo(" +
+                                                   button_count + ", 1)"));
+  ASSERT_TRUE(t->RunJavaScriptAndExtractBoolOrFail(
+      "isMappingEqualTo('xr-standard', 0)"));
+  ASSERT_TRUE(t->RunJavaScriptAndExtractBoolOrFail(
+      "isMappingEqualTo('xr-standard', 1)"));
 
   // Press the trigger and set the axis to a non-zero amount, so we can ensure
   // we aren't getting just default gamepad data.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 49bd6ed..edbf1e10 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -510,6 +510,7 @@
       "../browser/payments/has_enrolled_instrument_browsertest.cc",
       "../browser/payments/has_enrolled_instrument_query_quota_browsertest.cc",
       "../browser/payments/hybrid_request_skip_ui_browsertest.cc",
+      "../browser/payments/payment_handler_enable_delegations_browsertest.cc",
       "../browser/payments/payment_handler_exploit_browsertest.cc",
       "../browser/payments/payment_request_can_make_payment_browsertest.cc",
       "../browser/payments/personal_data_manager_test_util.cc",
@@ -1804,6 +1805,7 @@
         "../browser/payments/has_enrolled_instrument_browsertest.cc",
         "../browser/payments/has_enrolled_instrument_query_quota_browsertest.cc",
         "../browser/payments/manifest_verifier_browsertest.cc",
+        "../browser/payments/payment_handler_enable_delegations_browsertest.cc",
         "../browser/payments/payment_handler_exploit_browsertest.cc",
         "../browser/payments/payment_manifest_parser_browsertest.cc",
         "../browser/payments/payment_request_can_make_payment_browsertest.cc",
@@ -4083,6 +4085,7 @@
       "../browser/metrics/perf/metric_collector_unittest.cc",
       "../browser/metrics/perf/metric_provider_unittest.cc",
       "../browser/metrics/perf/perf_events_collector_unittest.cc",
+      "../browser/metrics/perf/perf_output_unittest.cc",
       "../browser/metrics/perf/process_type_collector_unittest.cc",
       "../browser/metrics/perf/profile_provider_chromeos_unittest.cc",
       "../browser/metrics/perf/windowed_incognito_observer_unittest.cc",
diff --git a/chrome/test/data/webui/settings/chromeos/os_people_page_test.js b/chrome/test/data/webui/settings/chromeos/os_people_page_test.js
index 83c3723a..11bd8b0 100644
--- a/chrome/test/data/webui/settings/chromeos/os_people_page_test.js
+++ b/chrome/test/data/webui/settings/chromeos/os_people_page_test.js
@@ -114,10 +114,14 @@
       await syncBrowserProxy.whenCalled('getSyncStatus');
       Polymer.dom.flush();
 
+      // Get page elements.
+      const profileIconEl = assert(peoplePage.$$('#profile-icon'));
+      const profileRowEl = assert(peoplePage.$$('#profile-row'));
+      const profileNameEl = assert(peoplePage.$$('#profile-name'));
+
       assertEquals(
-          browserProxy.fakeProfileInfo.name,
-          peoplePage.$$('#profile-name').textContent.trim());
-      const bg = peoplePage.$$('#profile-icon').style.backgroundImage;
+          browserProxy.fakeProfileInfo.name, profileNameEl.textContent.trim());
+      const bg = profileIconEl.style.backgroundImage;
       assertTrue(bg.includes(browserProxy.fakeProfileInfo.iconUrl));
 
       const iconDataUrl = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEA' +
@@ -126,11 +130,14 @@
           'profile-info-changed', {name: 'pushedName', iconUrl: iconDataUrl});
 
       Polymer.dom.flush();
-      assertEquals(
-          'pushedName', peoplePage.$$('#profile-name').textContent.trim());
-      const newBg = peoplePage.$$('#profile-icon').style.backgroundImage;
+      assertEquals('pushedName', profileNameEl.textContent.trim());
+      const newBg = profileIconEl.style.backgroundImage;
       assertTrue(newBg.includes(iconDataUrl));
 
+      // Profile row items aren't actionable.
+      assertFalse(profileIconEl.hasAttribute('actionable'));
+      assertFalse(profileRowEl.hasAttribute('actionable'));
+
       // Sub-page trigger is hidden.
       assertTrue(peoplePage.$$('#account-manager-subpage-trigger').hidden);
     });
@@ -147,11 +154,15 @@
       await syncBrowserProxy.whenCalled('getSyncStatus');
       Polymer.dom.flush();
 
+      // Get page elements.
+      const profileIconEl = assert(peoplePage.$$('#profile-icon'));
+      const profileRowEl = assert(peoplePage.$$('#profile-row'));
+      const profileNameEl = assert(peoplePage.$$('#profile-name'));
+
       chai.assert.include(
-          peoplePage.$$('#profile-icon').style.backgroundImage,
+          profileIconEl.style.backgroundImage,
           'data:image/png;base64,primaryAccountPicData');
-      assertEquals(
-          'Primary Account', peoplePage.$$('#profile-name').textContent.trim());
+      assertEquals('Primary Account', profileNameEl.textContent.trim());
 
       // Rather than trying to mock cr.sendWithPromise('getPluralString', ...)
       // just force an update.
@@ -160,6 +171,10 @@
           'primary@gmail.com, +2 more accounts',
           peoplePage.$$('#profile-label').textContent.trim());
 
+      // Profile row items are actionable.
+      assertTrue(profileIconEl.hasAttribute('actionable'));
+      assertTrue(profileRowEl.hasAttribute('actionable'));
+
       // Sub-page trigger is shown.
       const subpageTrigger = peoplePage.$$('#account-manager-subpage-trigger');
       assertFalse(subpageTrigger.hidden);
diff --git a/chrome/test/data/webui/settings/people_page_test.js b/chrome/test/data/webui/settings/people_page_test.js
index 0021ffb..df2c5e1f 100644
--- a/chrome/test/data/webui/settings/people_page_test.js
+++ b/chrome/test/data/webui/settings/people_page_test.js
@@ -699,6 +699,8 @@
         // Profile row items aren't actionable.
         const profileIcon = assert(peoplePage.$$('#profile-icon'));
         assertFalse(profileIcon.hasAttribute('actionable'));
+        const profileRow = assert(peoplePage.$$('#profile-row'));
+        assertFalse(profileRow.hasAttribute('actionable'));
         const subpageArrow = assert(peoplePage.$$('#profile-subpage-arrow'));
         assertFalse(subpageArrow.hasAttribute('actionable'));
 
diff --git a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
index cb37729..3eb5c38 100644
--- a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
+++ b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
@@ -27,6 +27,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using testing::_;
+using testing::AtLeast;
 using testing::Invoke;
 using testing::NiceMock;
 using testing::Return;
@@ -176,7 +177,9 @@
   void SetPipelineStartExpectations() {
     // The pipeline will be paused first, for the initial data buffering. Then
     // it will be resumed, once enough data is buffered to start playback.
-    EXPECT_CALL(*pipeline_backend_, GetCurrentPts());
+    // When starting media pipeline, GetCurrentPts will be called every
+    // kTimeUpdateInterval(250ms).
+    EXPECT_CALL(*pipeline_backend_, GetCurrentPts()).Times(AtLeast(1));
     EXPECT_CALL(*pipeline_backend_, Pause());
     EXPECT_CALL(*pipeline_backend_, SetPlaybackRate(1.0f));
     EXPECT_CALL(*pipeline_backend_, Resume());
diff --git a/chromeos/cryptohome/cryptohome_util.cc b/chromeos/cryptohome/cryptohome_util.cc
index 5731684..e6e056a 100644
--- a/chromeos/cryptohome/cryptohome_util.cc
+++ b/chromeos/cryptohome/cryptohome_util.cc
@@ -372,6 +372,7 @@
     case CRYPTOHOME_ERROR_FAILED_TO_EXTEND_PCR:
     case CRYPTOHOME_ERROR_FAILED_TO_READ_PCR:
     case CRYPTOHOME_ERROR_PCR_ALREADY_EXTENDED:
+    case CRYPTOHOME_ERROR_TPM_UPDATE_REQUIRED:
       NOTREACHED();
       return MOUNT_ERROR_FATAL;
   }
diff --git a/chromeos/dbus/concierge_client.cc b/chromeos/dbus/concierge_client.cc
index bc6e65f..eee532fd 100644
--- a/chromeos/dbus/concierge_client.cc
+++ b/chromeos/dbus/concierge_client.cc
@@ -26,6 +26,14 @@
 
   ~ConciergeClientImpl() override = default;
 
+  void AddVmObserver(VmObserver* observer) override {
+    vm_observer_list_.AddObserver(observer);
+  }
+
+  void RemoveVmObserver(VmObserver* observer) override {
+    vm_observer_list_.RemoveObserver(observer);
+  }
+
   void AddContainerObserver(ContainerObserver* observer) override {
     container_observer_list_.AddObserver(observer);
   }
@@ -42,6 +50,14 @@
     disk_image_observer_list_.RemoveObserver(observer);
   }
 
+  bool IsVmStartedSignalConnected() override {
+    return is_vm_started_signal_connected_;
+  }
+
+  bool IsVmStoppedSignalConnected() override {
+    return is_vm_stopped_signal_connected_;
+  }
+
   bool IsContainerStartupFailedSignalConnected() override {
     return is_container_startup_failed_signal_connected_;
   }
@@ -164,7 +180,24 @@
       const vm_tools::concierge::AttachUsbDeviceRequest& request,
       DBusMethodCallback<vm_tools::concierge::AttachUsbDeviceResponse> callback)
       override {
-    CallMethod(kAttachUsbDeviceMethod, request, std::move(callback));
+    dbus::MethodCall method_call(vm_tools::concierge::kVmConciergeInterface,
+                                 vm_tools::concierge::kAttachUsbDeviceMethod);
+    dbus::MessageWriter writer(&method_call);
+
+    if (!writer.AppendProtoAsArrayOfBytes(request)) {
+      LOG(ERROR) << "Failed to encode AttachUsbDeviceRequest protobuf";
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
+      return;
+    }
+
+    writer.AppendFileDescriptor(fd.get());
+
+    concierge_proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&ConciergeClientImpl::OnDBusProtoResponse<
+                           vm_tools::concierge::AttachUsbDeviceResponse>,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   }
 
   void DetachUsbDevice(
@@ -198,6 +231,20 @@
     }
     concierge_proxy_->ConnectToSignal(
         vm_tools::concierge::kVmConciergeInterface,
+        vm_tools::concierge::kVmStartedSignal,
+        base::BindRepeating(&ConciergeClientImpl::OnVmStartedSignal,
+                            weak_ptr_factory_.GetWeakPtr()),
+        base::BindOnce(&ConciergeClientImpl::OnSignalConnected,
+                       weak_ptr_factory_.GetWeakPtr()));
+    concierge_proxy_->ConnectToSignal(
+        vm_tools::concierge::kVmConciergeInterface,
+        vm_tools::concierge::kVmStoppedSignal,
+        base::BindRepeating(&ConciergeClientImpl::OnVmStoppedSignal,
+                            weak_ptr_factory_.GetWeakPtr()),
+        base::BindOnce(&ConciergeClientImpl::OnSignalConnected,
+                       weak_ptr_factory_.GetWeakPtr()));
+    concierge_proxy_->ConnectToSignal(
+        vm_tools::concierge::kVmConciergeInterface,
         vm_tools::concierge::kContainerStartupFailedSignal,
         base::BindRepeating(
             &ConciergeClientImpl::OnContainerStartupFailedSignal,
@@ -252,6 +299,38 @@
     std::move(callback).Run(std::move(reponse_proto));
   }
 
+  void OnVmStartedSignal(dbus::Signal* signal) {
+    DCHECK_EQ(signal->GetInterface(),
+              vm_tools::concierge::kVmConciergeInterface);
+    DCHECK_EQ(signal->GetMember(), vm_tools::concierge::kVmStartedSignal);
+
+    vm_tools::concierge::VmStartedSignal vm_started_signal;
+    dbus::MessageReader reader(signal);
+    if (!reader.PopArrayOfBytesAsProto(&vm_started_signal)) {
+      LOG(ERROR) << "Failed to parse proto from DBus Signal";
+      return;
+    }
+
+    for (auto& observer : vm_observer_list_)
+      observer.OnVmStarted(vm_started_signal);
+  }
+
+  void OnVmStoppedSignal(dbus::Signal* signal) {
+    DCHECK_EQ(signal->GetInterface(),
+              vm_tools::concierge::kVmConciergeInterface);
+    DCHECK_EQ(signal->GetMember(), vm_tools::concierge::kVmStoppedSignal);
+
+    vm_tools::concierge::VmStoppedSignal vm_stopped_signal;
+    dbus::MessageReader reader(signal);
+    if (!reader.PopArrayOfBytesAsProto(&vm_stopped_signal)) {
+      LOG(ERROR) << "Failed to parse proto from DBus Signal";
+      return;
+    }
+
+    for (auto& observer : vm_observer_list_)
+      observer.OnVmStopped(vm_stopped_signal);
+  }
+
   void OnContainerStartupFailedSignal(dbus::Signal* signal) {
     DCHECK_EQ(signal->GetInterface(),
               vm_tools::concierge::kVmConciergeInterface);
@@ -296,7 +375,12 @@
     if (!is_connected)
       LOG(ERROR) << "Failed to connect to signal: " << signal_name;
 
-    if (signal_name == vm_tools::concierge::kContainerStartupFailedSignal) {
+    if (signal_name == vm_tools::concierge::kVmStartedSignal) {
+      is_vm_started_signal_connected_ = is_connected;
+    } else if (signal_name == vm_tools::concierge::kVmStoppedSignal) {
+      is_vm_stopped_signal_connected_ = is_connected;
+    } else if (signal_name ==
+               vm_tools::concierge::kContainerStartupFailedSignal) {
       is_container_startup_failed_signal_connected_ = is_connected;
     } else if (signal_name == vm_tools::concierge::kDiskImageProgressSignal) {
       is_disk_import_progress_signal_connected_ = is_connected;
@@ -307,9 +391,12 @@
 
   dbus::ObjectProxy* concierge_proxy_ = nullptr;
 
+  base::ObserverList<VmObserver>::Unchecked vm_observer_list_;
   base::ObserverList<ContainerObserver>::Unchecked container_observer_list_;
   base::ObserverList<DiskImageObserver>::Unchecked disk_image_observer_list_;
 
+  bool is_vm_started_signal_connected_ = false;
+  bool is_vm_stopped_signal_connected_ = false;
   bool is_container_startup_failed_signal_connected_ = false;
   bool is_disk_import_progress_signal_connected_ = false;
 
diff --git a/chromeos/dbus/concierge_client.h b/chromeos/dbus/concierge_client.h
index 32a0c99..7982e4f6 100644
--- a/chromeos/dbus/concierge_client.h
+++ b/chromeos/dbus/concierge_client.h
@@ -20,6 +20,21 @@
 // start and stop VMs, as well as for disk image management.
 class COMPONENT_EXPORT(CHROMEOS_DBUS) ConciergeClient : public DBusClient {
  public:
+  // Used for observing VMs starting and stopping.
+  class VmObserver {
+   public:
+    // OnVmStarted is signaled by Concierge when a VM starts.
+    virtual void OnVmStarted(
+        const vm_tools::concierge::VmStartedSignal& signal) = 0;
+
+    // OnVmStopped is signaled by Concierge when a VM stops.
+    virtual void OnVmStopped(
+        const vm_tools::concierge::VmStoppedSignal& signal) = 0;
+
+   protected:
+    virtual ~VmObserver() = default;
+  };
+
   // Used for observing all concierge signals related to running
   // containers (e.g. startup).
   class ContainerObserver {
@@ -48,6 +63,11 @@
     virtual ~DiskImageObserver() = default;
   };
 
+  // Adds an observer for VM start and stop.
+  virtual void AddVmObserver(VmObserver* observer) = 0;
+  // Removes an observer if added.
+  virtual void RemoveVmObserver(VmObserver* observer) = 0;
+
   // Adds an observer for container startup.
   virtual void AddContainerObserver(ContainerObserver* observer) = 0;
   // Removes an observer if added.
@@ -58,6 +78,11 @@
   // Adds an observer for disk image operations.
   virtual void RemoveDiskImageObserver(DiskImageObserver* observer) = 0;
 
+  // IsVmSartedSignalConnected and IsVmStoppedSignalConnected must return true
+  // before RestartCrostini is called.
+  virtual bool IsVmStartedSignalConnected() = 0;
+  virtual bool IsVmStoppedSignalConnected() = 0;
+
   // IsContainerStartupFailedSignalConnected must return true before
   // StartContainer is called.
   virtual bool IsContainerStartupFailedSignalConnected() = 0;
diff --git a/chromeos/dbus/debug_daemon_client.h b/chromeos/dbus/debug_daemon_client.h
index cae11477..eca1ff2 100644
--- a/chromeos/dbus/debug_daemon_client.h
+++ b/chromeos/dbus/debug_daemon_client.h
@@ -23,6 +23,10 @@
 #include "chromeos/dbus/dbus_method_call_status.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
+namespace metrics {
+class DebugdClientProvider;
+}  // namespace metrics
+
 namespace chromeos {
 
 // A DbusLibraryError represents an error response received from D-Bus.
@@ -260,6 +264,10 @@
   static std::unique_ptr<DebugDaemonClient> Create();
 
  protected:
+  // For calling Init() in initiating a DebugDaemonClient instance for private
+  // connections.
+  friend class metrics::DebugdClientProvider;
+
   // Create() should be used instead.
   DebugDaemonClient();
 
diff --git a/chromeos/dbus/fake_cicerone_client.cc b/chromeos/dbus/fake_cicerone_client.cc
index 45fe2f7..67a9547 100644
--- a/chromeos/dbus/fake_cicerone_client.cc
+++ b/chromeos/dbus/fake_cicerone_client.cc
@@ -209,18 +209,18 @@
         FROM_HERE,
         base::BindOnce(&FakeCiceroneClient::NotifyLxdContainerStarting,
                        base::Unretained(this), std::move(signal)));
-  }
-  if (lxd_container_starting_signal_status_ ==
-      vm_tools::cicerone::LxdContainerStartingSignal::STARTED) {
-    // Trigger CiceroneClient::Observer::NotifyContainerStartedSignal.
-    vm_tools::cicerone::ContainerStartedSignal signal;
-    signal.set_owner_id(request.owner_id());
-    signal.set_vm_name(request.vm_name());
-    signal.set_container_name(request.container_name());
-    signal.set_container_username(last_container_username_);
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(&FakeCiceroneClient::NotifyContainerStarted,
-                                  base::Unretained(this), std::move(signal)));
+
+    if (send_container_started_signal_) {
+      // Trigger CiceroneClient::Observer::NotifyContainerStartedSignal.
+      vm_tools::cicerone::ContainerStartedSignal signal;
+      signal.set_owner_id(request.owner_id());
+      signal.set_vm_name(request.vm_name());
+      signal.set_container_name(request.container_name());
+      signal.set_container_username(last_container_username_);
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::BindOnce(&FakeCiceroneClient::NotifyContainerStarted,
+                                    base::Unretained(this), std::move(signal)));
+    }
   }
 }
 
diff --git a/chromeos/dbus/fake_cicerone_client.h b/chromeos/dbus/fake_cicerone_client.h
index 0b381411..f854294 100644
--- a/chromeos/dbus/fake_cicerone_client.h
+++ b/chromeos/dbus/fake_cicerone_client.h
@@ -233,6 +233,10 @@
     lxd_container_os_release_ = std::move(os_release);
   }
 
+  void set_send_container_started_signal(bool send) {
+    send_container_started_signal_ = send;
+  }
+
   // Additional functions to allow tests to trigger Signals.
   void NotifyLxdContainerCreated(
       const vm_tools::cicerone::LxdContainerCreatedSignal& signal);
@@ -272,6 +276,7 @@
   bool is_import_lxd_container_progress_signal_connected_ = true;
 
   std::string last_container_username_;
+  bool send_container_started_signal_ = true;
 
   vm_tools::cicerone::LxdContainerCreatedSignal_Status
       lxd_container_created_signal_status_ =
diff --git a/chromeos/dbus/fake_concierge_client.cc b/chromeos/dbus/fake_concierge_client.cc
index 8e8793b..6adf915 100644
--- a/chromeos/dbus/fake_concierge_client.cc
+++ b/chromeos/dbus/fake_concierge_client.cc
@@ -18,6 +18,14 @@
 }
 FakeConciergeClient::~FakeConciergeClient() = default;
 
+void FakeConciergeClient::AddVmObserver(VmObserver* observer) {
+  vm_observer_list_.AddObserver(observer);
+}
+
+void FakeConciergeClient::RemoveVmObserver(VmObserver* observer) {
+  vm_observer_list_.RemoveObserver(observer);
+}
+
 void FakeConciergeClient::AddContainerObserver(ContainerObserver* observer) {
   container_observer_list_.AddObserver(observer);
 }
@@ -34,6 +42,14 @@
   disk_image_observer_list_.RemoveObserver(observer);
 }
 
+bool FakeConciergeClient::IsVmStartedSignalConnected() {
+  return is_vm_started_signal_connected_;
+}
+
+bool FakeConciergeClient::IsVmStoppedSignalConnected() {
+  return is_vm_stopped_signal_connected_;
+}
+
 bool FakeConciergeClient::IsContainerStartupFailedSignalConnected() {
   return is_container_startup_failed_signal_connected_;
 }
diff --git a/chromeos/dbus/fake_concierge_client.h b/chromeos/dbus/fake_concierge_client.h
index da6c963a4..5baf99e 100644
--- a/chromeos/dbus/fake_concierge_client.h
+++ b/chromeos/dbus/fake_concierge_client.h
@@ -22,10 +22,15 @@
   ~FakeConciergeClient() override;
 
   // ConciergeClient:
+  void AddVmObserver(VmObserver* observer) override;
+  void RemoveVmObserver(VmObserver* observer) override;
   void AddContainerObserver(ContainerObserver* observer) override;
   void RemoveContainerObserver(ContainerObserver* observer) override;
   void AddDiskImageObserver(DiskImageObserver* observer) override;
   void RemoveDiskImageObserver(DiskImageObserver* observer) override;
+
+  bool IsVmStartedSignalConnected() override;
+  bool IsVmStoppedSignalConnected() override;
   bool IsContainerStartupFailedSignalConnected() override;
   bool IsDiskImageProgressSignalConnected() override;
   void CreateDiskImage(
@@ -116,6 +121,12 @@
   bool detach_usb_device_called() const { return detach_usb_device_called_; }
   bool list_usb_devices_called() const { return list_usb_devices_called_; }
   bool start_arc_vm_called() const { return start_arc_vm_called_; }
+  void set_vm_started_signal_connected(bool connected) {
+    is_vm_started_signal_connected_ = connected;
+  }
+  void set_vm_stopped_signal_connected(bool connected) {
+    is_vm_stopped_signal_connected_ = connected;
+  }
   void set_container_startup_failed_signal_connected(bool connected) {
     is_container_startup_failed_signal_connected_ = connected;
   }
@@ -238,6 +249,8 @@
   bool detach_usb_device_called_ = false;
   bool list_usb_devices_called_ = false;
   bool start_arc_vm_called_ = false;
+  bool is_vm_started_signal_connected_ = true;
+  bool is_vm_stopped_signal_connected_ = true;
   bool is_container_startup_failed_signal_connected_ = true;
   bool is_disk_image_progress_signal_connected_ = true;
 
@@ -264,6 +277,8 @@
   std::vector<vm_tools::concierge::DiskImageStatusResponse>
       disk_image_status_signals_;
 
+  base::ObserverList<VmObserver>::Unchecked vm_observer_list_;
+
   base::ObserverList<ContainerObserver>::Unchecked container_observer_list_;
 
   base::ObserverList<DiskImageObserver>::Unchecked disk_image_observer_list_;
diff --git a/chromeos/services/assistant/assistant_state_proxy.cc b/chromeos/services/assistant/assistant_state_proxy.cc
index 98ab7c2..d4ca3e3 100644
--- a/chromeos/services/assistant/assistant_state_proxy.cc
+++ b/chromeos/services/assistant/assistant_state_proxy.cc
@@ -50,7 +50,7 @@
 }
 
 void AssistantStateProxy::OnAssistantStatusChanged(
-    ash::mojom::VoiceInteractionState state) {
+    ash::mojom::AssistantState state) {
   UpdateAssistantStatus(state);
 }
 
diff --git a/chromeos/services/assistant/assistant_state_proxy.h b/chromeos/services/assistant/assistant_state_proxy.h
index 977b948..e8185211 100644
--- a/chromeos/services/assistant/assistant_state_proxy.h
+++ b/chromeos/services/assistant/assistant_state_proxy.h
@@ -10,7 +10,6 @@
 
 #include "ash/public/cpp/assistant/assistant_state_base.h"
 #include "ash/public/mojom/assistant_state_controller.mojom.h"
-#include "ash/public/mojom/voice_interaction_controller.mojom.h"
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
@@ -41,8 +40,7 @@
 
  private:
   // AssistantStateObserver:
-  void OnAssistantStatusChanged(
-      ash::mojom::VoiceInteractionState state) override;
+  void OnAssistantStatusChanged(ash::mojom::AssistantState state) override;
   void OnAssistantFeatureAllowedChanged(
       ash::mojom::AssistantAllowedState state) override;
   void OnLocaleChanged(const std::string& locale) override;
diff --git a/components/download/internal/common/download_db_cache.cc b/components/download/internal/common/download_db_cache.cc
index fc6c029..d1fdf2d 100644
--- a/components/download/internal/common/download_db_cache.cc
+++ b/components/download/internal/common/download_db_cache.cc
@@ -171,18 +171,6 @@
 }
 
 void DownloadDBCache::OnDownloadUpdated(DownloadItem* download) {
-  // TODO(crbug.com/778425): Properly handle fail/resume/retry for downloads
-  // that are in the INTERRUPTED state for a long time.
-  if (!base::FeatureList::IsEnabled(features::kDownloadDBForNewDownloads)) {
-    // If history service is still managing in-progress download, we can safely
-    // remove a download from the in-progress DB whenever it is in the terminal
-    // state. Otherwise, we need to propagate the completed download to
-    // history service before we can remove it.
-    if (download->IsDone()) {
-      OnDownloadRemoved(download);
-      return;
-    }
-  }
   DownloadDBEntry entry = CreateDownloadDBEntryFromItem(
       *(static_cast<DownloadItemImpl*>(download)));
   AddOrReplaceEntry(entry);
diff --git a/components/download/internal/common/download_task_runner.cc b/components/download/internal/common/download_task_runner.cc
index cb198e7e..d34a535 100644
--- a/components/download/internal/common/download_task_runner.cc
+++ b/components/download/internal/common/download_task_runner.cc
@@ -35,6 +35,9 @@
 base::LazyInstance<scoped_refptr<base::SingleThreadTaskRunner>>::
     DestructorAtExit g_io_task_runner = LAZY_INSTANCE_INITIALIZER;
 
+base::LazyInstance<scoped_refptr<base::SequencedTaskRunner>>::DestructorAtExit
+    g_db_task_runner = LAZY_INSTANCE_INITIALIZER;
+
 // Lock to protect |g_io_task_runner|
 base::Lock& GetIOTaskRunnerLock() {
   static base::NoDestructor<base::Lock> instance;
@@ -63,4 +66,14 @@
   return g_io_task_runner.Get();
 }
 
+void SetDownloadDBTaskRunnerForTesting(
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
+  DCHECK(task_runner);
+  g_db_task_runner.Get() = task_runner;
+}
+
+scoped_refptr<base::SequencedTaskRunner> GetDownloadDBTaskRunnerForTesting() {
+  return g_db_task_runner.Get();
+}
+
 }  // namespace download
diff --git a/components/download/internal/common/in_progress_download_manager.cc b/components/download/internal/common/in_progress_download_manager.cc
index 694651a..41531ef 100644
--- a/components/download/internal/common/in_progress_download_manager.cc
+++ b/components/download/internal/common/in_progress_download_manager.cc
@@ -353,6 +353,10 @@
 
   download_db_cache_ =
       std::make_unique<DownloadDBCache>(std::move(download_db));
+  if (GetDownloadDBTaskRunnerForTesting()) {
+    download_db_cache_->SetTimerTaskRunnerForTesting(
+        GetDownloadDBTaskRunnerForTesting());
+  }
   download_db_cache_->Initialize(base::BindOnce(
       &InProgressDownloadManager::OnDBInitialized, weak_factory_.GetWeakPtr()));
 }
@@ -581,36 +585,34 @@
         CreateDownloadEntryFromDownloadDBEntry(entry);
     if (download_entry)
       download_entries_[download_entry->guid] = download_entry.value();
-    if (base::FeatureList::IsEnabled(features::kDownloadDBForNewDownloads)) {
-      auto item = CreateDownloadItemImpl(this, entry);
-      if (!item)
-        continue;
-      uint32_t download_id = item->GetId();
-      // Remove entries with duplicate ids.
-      if (download_id != DownloadItem::kInvalidId &&
-          base::Contains(download_ids, download_id)) {
-        RemoveInProgressDownload(item->GetGuid());
-        num_duplicates++;
-        continue;
-      }
-#if defined(OS_ANDROID)
-      const base::FilePath& path = item->GetTargetFilePath();
-      if (path.IsContentUri()) {
-        base::FilePath display_name = GetDownloadDisplayName(path);
-        // If a download doesn't have a display name, remove it.
-        if (display_name.empty()) {
-          RemoveInProgressDownload(item->GetGuid());
-          continue;
-        } else {
-          item->SetDisplayName(display_name);
-        }
-      }
-#endif
-      item->AddObserver(download_db_cache_.get());
-      OnNewDownloadCreated(item.get());
-      in_progress_downloads_.emplace_back(std::move(item));
-      download_ids.insert(download_id);
+    auto item = CreateDownloadItemImpl(this, entry);
+    if (!item)
+      continue;
+    uint32_t download_id = item->GetId();
+    // Remove entries with duplicate ids.
+    if (download_id != DownloadItem::kInvalidId &&
+        base::Contains(download_ids, download_id)) {
+      RemoveInProgressDownload(item->GetGuid());
+      num_duplicates++;
+      continue;
     }
+#if defined(OS_ANDROID)
+    const base::FilePath& path = item->GetTargetFilePath();
+    if (path.IsContentUri()) {
+      base::FilePath display_name = GetDownloadDisplayName(path);
+      // If a download doesn't have a display name, remove it.
+      if (display_name.empty()) {
+        RemoveInProgressDownload(item->GetGuid());
+        continue;
+      } else {
+        item->SetDisplayName(display_name);
+      }
+    }
+#endif
+    item->AddObserver(download_db_cache_.get());
+    OnNewDownloadCreated(item.get());
+    in_progress_downloads_.emplace_back(std::move(item));
+    download_ids.insert(download_id);
   }
   if (num_duplicates > 0)
     RecordDuplicateInProgressDownloadIdCount(num_duplicates);
diff --git a/components/download/public/common/download_features.cc b/components/download/public/common/download_features.cc
index 3411080..c40c501 100644
--- a/components/download/public/common/download_features.cc
+++ b/components/download/public/common/download_features.cc
@@ -30,9 +30,6 @@
 #endif
 };
 
-const base::Feature kDownloadDBForNewDownloads{
-    "DownloadDBForNewDownloads", base::FEATURE_ENABLED_BY_DEFAULT};
-
 #if defined(OS_ANDROID)
 const base::Feature kRefreshExpirationDate{"RefreshExpirationDate",
                                            base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/components/download/public/common/download_features.h b/components/download/public/common/download_features.h
index 345844aaf..0c8bec9 100644
--- a/components/download/public/common/download_features.h
+++ b/components/download/public/common/download_features.h
@@ -23,11 +23,6 @@
 // Whether a download can be handled by parallel jobs.
 COMPONENTS_DOWNLOAD_EXPORT extern const base::Feature kParallelDownloading;
 
-// Whether metadata for new in-progress downloads will be be stored in download
-// DB, rather than history DB.
-COMPONENTS_DOWNLOAD_EXPORT extern const base::Feature
-    kDownloadDBForNewDownloads;
-
 #if defined(OS_ANDROID)
 // Whether download expiration date will be refreshed on resumption.
 COMPONENTS_DOWNLOAD_EXPORT extern const base::Feature kRefreshExpirationDate;
diff --git a/components/download/public/common/download_task_runner.h b/components/download/public/common/download_task_runner.h
index 5f58790..35ec925 100644
--- a/components/download/public/common/download_task_runner.h
+++ b/components/download/public/common/download_task_runner.h
@@ -23,6 +23,14 @@
 COMPONENTS_DOWNLOAD_EXPORT scoped_refptr<base::SingleThreadTaskRunner>
 GetIOTaskRunner();
 
+// Sets the task runner for download DB, must be called on UI thread.
+COMPONENTS_DOWNLOAD_EXPORT void SetDownloadDBTaskRunnerForTesting(
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+
+// Gets the task runner for download DB, must be called on UI thread.
+COMPONENTS_DOWNLOAD_EXPORT scoped_refptr<base::SequencedTaskRunner>
+GetDownloadDBTaskRunnerForTesting();
+
 }  // namespace download
 
 #endif  // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_TASK_RUNNER_H_
diff --git a/components/media_message_center/media_notification_container.h b/components/media_message_center/media_notification_container.h
index 46c4d2b..154c9ba2 100644
--- a/components/media_message_center/media_notification_container.h
+++ b/components/media_message_center/media_notification_container.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_CONTAINER_H_
 
 #include "base/component_export.h"
+#include "services/media_session/public/mojom/media_session.mojom.h"
 
 namespace media_message_center {
 
@@ -16,6 +17,13 @@
  public:
   // Called when MediaNotificationView's expanded state changes.
   virtual void OnExpanded(bool expanded) = 0;
+
+  // Called when the MediaSessionInfo changes.
+  virtual void OnMediaSessionInfoChanged(
+      const media_session::mojom::MediaSessionInfoPtr& session_info) = 0;
+
+  // Called when MediaNotificationView's foreground color changes.
+  virtual void OnForegoundColorChanged(SkColor color) = 0;
 };
 
 }  // namespace media_message_center
diff --git a/components/media_message_center/media_notification_item.cc b/components/media_message_center/media_notification_item.cc
index 21c3cb54..207bdf8 100644
--- a/components/media_message_center/media_notification_item.cc
+++ b/components/media_message_center/media_notification_item.cc
@@ -226,6 +226,12 @@
   MaybeHideOrShowNotification();
 }
 
+void MediaNotificationItem::Dismiss() {
+  if (media_controller_remote_.is_bound())
+    media_controller_remote_->Stop();
+  controller_->RemoveItem(request_id_);
+}
+
 void MediaNotificationItem::Freeze() {
   if (frozen_)
     return;
diff --git a/components/media_message_center/media_notification_item.h b/components/media_message_center/media_notification_item.h
index 63f91cb..82b1f98 100644
--- a/components/media_message_center/media_notification_item.h
+++ b/components/media_message_center/media_notification_item.h
@@ -92,6 +92,10 @@
       mojo::Remote<media_session::mojom::MediaController> controller,
       media_session::mojom::MediaSessionInfoPtr session_info);
 
+  // This will stop the media session associated with this item. The item will
+  // then call |MediaNotificationController::RemoveItem()| to ensure removal.
+  void Dismiss();
+
   // This will freeze the item and start a timer to destroy the item after
   // some time has passed.
   void Freeze();
diff --git a/components/media_message_center/media_notification_view.cc b/components/media_message_center/media_notification_view.cc
index 49780493..64e3ff03 100644
--- a/components/media_message_center/media_notification_view.cc
+++ b/components/media_message_center/media_notification_view.cc
@@ -282,6 +282,8 @@
 
   UpdateActionButtonsVisibility();
 
+  container_->OnMediaSessionInfoChanged(session_info);
+
   PreferredSizeChanged();
   Layout();
   SchedulePaint();
@@ -481,6 +483,8 @@
 
     button->SchedulePaint();
   }
+
+  container_->OnForegoundColorChanged(foreground);
 }
 
 }  // namespace media_message_center
diff --git a/components/media_message_center/media_notification_view_unittest.cc b/components/media_message_center/media_notification_view_unittest.cc
index eb1d49a8..a467a09 100644
--- a/components/media_message_center/media_notification_view_unittest.cc
+++ b/components/media_message_center/media_notification_view_unittest.cc
@@ -84,6 +84,10 @@
 
   // MediaNotificationContainer implementation.
   MOCK_METHOD1(OnExpanded, void(bool expanded));
+  MOCK_METHOD1(
+      OnMediaSessionInfoChanged,
+      void(const media_session::mojom::MediaSessionInfoPtr& session_info));
+  MOCK_METHOD1(OnForegoundColorChanged, void(SkColor color));
 
   MediaNotificationView* view() const { return view_.get(); }
   void SetView(std::unique_ptr<MediaNotificationView> view) {
@@ -375,6 +379,8 @@
   EnableAction(MediaSessionAction::kPlay);
   EnableAction(MediaSessionAction::kPause);
 
+  EXPECT_CALL(container(), OnMediaSessionInfoChanged(_));
+
   auto* button = GetButtonForAction(MediaSessionAction::kPlay);
   base::string16 tooltip = button->GetTooltipText(gfx::Point());
   EXPECT_FALSE(tooltip.empty());
@@ -420,6 +426,7 @@
 TEST_F(MediaNotificationViewTest, PauseButtonClick) {
   EXPECT_CALL(controller(), LogMediaSessionActionButtonPressed(_));
   EnableAction(MediaSessionAction::kPause);
+  EXPECT_CALL(container(), OnMediaSessionInfoChanged(_));
 
   EXPECT_EQ(0, media_controller()->suspend_count());
 
@@ -692,6 +699,7 @@
   int title_artist_width = title_artist_row()->width();
   const SkColor accent = header_row()->accent_color_for_testing();
   gfx::Size size = view()->size();
+  EXPECT_CALL(container(), OnForegoundColorChanged(_)).Times(2);
 
   SkBitmap image;
   image.allocN32Pixels(10, 10);
@@ -900,6 +908,7 @@
   SkBitmap image;
   image.allocN32Pixels(10, 10);
   image.eraseColor(SK_ColorMAGENTA);
+  EXPECT_CALL(container(), OnForegoundColorChanged(_)).Times(0);
 
   GetItem()->Freeze();
   GetItem()->MediaControllerImageChanged(
@@ -912,6 +921,8 @@
   EnableAction(MediaSessionAction::kPlay);
   EnableAction(MediaSessionAction::kPause);
 
+  EXPECT_CALL(container(), OnMediaSessionInfoChanged(_)).Times(0);
+
   GetItem()->Freeze();
 
   EXPECT_TRUE(GetButtonForAction(MediaSessionAction::kPlay));
diff --git a/components/mirroring/mojom/resource_provider.mojom b/components/mirroring/mojom/resource_provider.mojom
index 6955008..d46420d 100644
--- a/components/mirroring/mojom/resource_provider.mojom
+++ b/components/mirroring/mojom/resource_provider.mojom
@@ -30,9 +30,10 @@
   BindGpu(pending_receiver<viz.mojom.Gpu> receiver);
   GetVideoCaptureHost(media.mojom.VideoCaptureHost& request);
   GetNetworkContext(pending_receiver<network.mojom.NetworkContext> receiver);
-  CreateAudioStream(AudioStreamCreatorClient client,
+  CreateAudioStream(pending_remote<AudioStreamCreatorClient> client,
                     media.mojom.AudioParameters param,
                     uint32 shared_memory_count);
-  ConnectToRemotingSource(media.mojom.Remoter remoter,
-                          media.mojom.RemotingSource& request);
+  ConnectToRemotingSource(
+      pending_remote<media.mojom.Remoter> remoter,
+      pending_receiver<media.mojom.RemotingSource> receiver);
 };
diff --git a/components/mirroring/service/captured_audio_input.cc b/components/mirroring/service/captured_audio_input.cc
index 7137fc5..a8be7a4 100644
--- a/components/mirroring/service/captured_audio_input.cc
+++ b/components/mirroring/service/captured_audio_input.cc
@@ -12,8 +12,7 @@
 
 CapturedAudioInput::CapturedAudioInput(StreamCreatorCallback callback)
     : stream_creator_callback_(std::move(callback)),
-      stream_client_binding_(this),
-      stream_creator_client_binding_(this) {
+      stream_client_binding_(this) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
   DCHECK(!stream_creator_callback_.is_null());
 }
@@ -29,9 +28,9 @@
   DCHECK(delegate);
   DCHECK(!delegate_);
   delegate_ = delegate;
-  mojom::AudioStreamCreatorClientPtr client;
-  stream_creator_client_binding_.Bind(mojo::MakeRequest(&client));
-  stream_creator_callback_.Run(std::move(client), params, total_segments);
+  stream_creator_callback_.Run(
+      stream_creator_client_receiver_.BindNewPipeAndPassRemote(), params,
+      total_segments);
 }
 
 void CapturedAudioInput::RecordStream() {
diff --git a/components/mirroring/service/captured_audio_input.h b/components/mirroring/service/captured_audio_input.h
index b0f79aa..11fe9e7 100644
--- a/components/mirroring/service/captured_audio_input.h
+++ b/components/mirroring/service/captured_audio_input.h
@@ -13,6 +13,7 @@
 #include "media/audio/audio_input_ipc.h"
 #include "media/mojo/mojom/audio_input_stream.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 namespace mirroring {
 
@@ -23,10 +24,10 @@
       public mojom::AudioStreamCreatorClient,
       public media::mojom::AudioInputStreamClient {
  public:
-  using StreamCreatorCallback =
-      base::RepeatingCallback<void(mojom::AudioStreamCreatorClientPtr client,
-                                   const media::AudioParameters& params,
-                                   uint32_t total_segments)>;
+  using StreamCreatorCallback = base::RepeatingCallback<void(
+      mojo::PendingRemote<mojom::AudioStreamCreatorClient> client,
+      const media::AudioParameters& params,
+      uint32_t total_segments)>;
   explicit CapturedAudioInput(StreamCreatorCallback callback);
   ~CapturedAudioInput() override;
 
@@ -55,7 +56,8 @@
 
   const StreamCreatorCallback stream_creator_callback_;
   mojo::Binding<media::mojom::AudioInputStreamClient> stream_client_binding_;
-  mojo::Binding<mojom::AudioStreamCreatorClient> stream_creator_client_binding_;
+  mojo::Receiver<mojom::AudioStreamCreatorClient>
+      stream_creator_client_receiver_{this};
   media::AudioInputIPCDelegate* delegate_ = nullptr;
   media::mojom::AudioInputStreamPtr stream_;
 
diff --git a/components/mirroring/service/captured_audio_input_unittest.cc b/components/mirroring/service/captured_audio_input_unittest.cc
index 888078e..1b4bb30 100644
--- a/components/mirroring/service/captured_audio_input_unittest.cc
+++ b/components/mirroring/service/captured_audio_input_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/test/task_environment.h"
 #include "media/base/audio_parameters.h"
 #include "media/mojo/mojom/audio_data_pipe.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/system/buffer.h"
 #include "mojo/public/cpp/system/platform_handle.h"
@@ -53,10 +54,11 @@
 
   ~CapturedAudioInputTest() override { task_environment_.RunUntilIdle(); }
 
-  void CreateMockStream(bool initially_muted,
-                        mojom::AudioStreamCreatorClientPtr client,
-                        const media::AudioParameters& params,
-                        uint32_t total_segments) {
+  void CreateMockStream(
+      bool initially_muted,
+      mojo::PendingRemote<mojom::AudioStreamCreatorClient> client,
+      const media::AudioParameters& params,
+      uint32_t total_segments) {
     EXPECT_EQ(base::SyncSocket::kInvalidHandle, socket_.handle());
     EXPECT_FALSE(stream_);
     media::mojom::AudioInputStreamPtr stream_ptr;
@@ -67,7 +69,9 @@
     base::CancelableSyncSocket foreign_socket;
     EXPECT_TRUE(
         base::CancelableSyncSocket::CreatePair(&socket_, &foreign_socket));
-    client->StreamCreated(
+    mojo::Remote<mojom::AudioStreamCreatorClient> audio_client(
+        std::move(client));
+    audio_client->StreamCreated(
         std::move(stream_ptr), mojo::MakeRequest(&stream_client_),
         {base::in_place, base::ReadOnlySharedMemoryRegion::Create(1024).region,
          mojo::WrapPlatformFile(foreign_socket.Release())},
diff --git a/components/mirroring/service/media_remoter.cc b/components/mirroring/service/media_remoter.cc
index a2e145f2..9edb5ff 100644
--- a/components/mirroring/service/media_remoter.cc
+++ b/components/mirroring/service/media_remoter.cc
@@ -27,17 +27,15 @@
     : client_(client),
       sink_metadata_(sink_metadata),
       message_dispatcher_(message_dispatcher),
-      binding_(this),
       cast_environment_(nullptr),
       transport_(nullptr),
       state_(MIRRORING) {
   DCHECK(client_);
   DCHECK(message_dispatcher_);
 
-  media::mojom::RemoterPtr remoter;
-  binding_.Bind(mojo::MakeRequest(&remoter));
-  client_->ConnectToRemotingSource(std::move(remoter),
-                                   mojo::MakeRequest(&remoting_source_));
+  client_->ConnectToRemotingSource(
+      receiver_.BindNewPipeAndPassRemote(),
+      remoting_source_.BindNewPipeAndPassReceiver());
   remoting_source_->OnSinkAvailable(sink_metadata_.Clone());
 }
 
diff --git a/components/mirroring/service/media_remoter.h b/components/mirroring/service/media_remoter.h
index dbedaa5..b3ab1f41 100644
--- a/components/mirroring/service/media_remoter.h
+++ b/components/mirroring/service/media_remoter.h
@@ -11,6 +11,8 @@
 #include "media/mojo/mojom/remoting.mojom.h"
 #include "media/mojo/mojom/remoting_common.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace media {
 namespace cast {
@@ -48,8 +50,9 @@
 
     // Connects the |remoter| with a source tab.
     virtual void ConnectToRemotingSource(
-        media::mojom::RemoterPtr remoter,
-        media::mojom::RemotingSourceRequest source_request) = 0;
+        mojo::PendingRemote<media::mojom::Remoter> remoter,
+        mojo::PendingReceiver<media::mojom::RemotingSource>
+            source_receiver) = 0;
 
     // Requests to start remoting. StartRpcMessaging() / OnRemotingStartFailed()
     // will be called when starting succeeds / fails.
@@ -108,8 +111,8 @@
   Client* const client_;  // Outlives this class.
   const media::mojom::RemotingSinkMetadata sink_metadata_;
   MessageDispatcher* const message_dispatcher_;  // Outlives this class.
-  mojo::Binding<media::mojom::Remoter> binding_;
-  media::mojom::RemotingSourcePtr remoting_source_;
+  mojo::Receiver<media::mojom::Remoter> receiver_{this};
+  mojo::Remote<media::mojom::RemotingSource> remoting_source_;
   scoped_refptr<media::cast::CastEnvironment> cast_environment_;
   std::unique_ptr<RemotingSender> audio_sender_;
   std::unique_ptr<RemotingSender> video_sender_;
diff --git a/components/mirroring/service/media_remoter_unittest.cc b/components/mirroring/service/media_remoter_unittest.cc
index d6ddf87..9ae9d72d 100644
--- a/components/mirroring/service/media_remoter_unittest.cc
+++ b/components/mirroring/service/media_remoter_unittest.cc
@@ -84,10 +84,11 @@
 
   // MediaRemoter::Client implementation.
   void ConnectToRemotingSource(
-      media::mojom::RemoterPtr remoter,
-      media::mojom::RemotingSourceRequest source_request) override {
-    remoter_ = std::move(remoter);
-    remoting_source_.Bind(std::move(source_request));
+      mojo::PendingRemote<media::mojom::Remoter> remoter,
+      mojo::PendingReceiver<media::mojom::RemotingSource> source_receiver)
+      override {
+    remoter_.Bind(std::move(remoter));
+    remoting_source_.Bind(std::move(source_receiver));
     OnConnectToRemotingSource();
   }
 
@@ -176,7 +177,7 @@
   MessageDispatcher message_dispatcher_;
   const media::mojom::RemotingSinkMetadata sink_metadata_;
   MockRemotingSource remoting_source_;
-  media::mojom::RemoterPtr remoter_;
+  mojo::Remote<media::mojom::Remoter> remoter_;
   std::unique_ptr<MediaRemoter> media_remoter_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaRemoterTest);
diff --git a/components/mirroring/service/session.cc b/components/mirroring/service/session.cc
index 3a93e2f..93c9d8b 100644
--- a/components/mirroring/service/session.cc
+++ b/components/mirroring/service/session.cc
@@ -787,9 +787,10 @@
   // TODO(xjz): Log the |error_message| in the mirroring logs.
 }
 
-void Session::CreateAudioStream(mojom::AudioStreamCreatorClientPtr client,
-                                const media::AudioParameters& params,
-                                uint32_t shared_memory_count) {
+void Session::CreateAudioStream(
+    mojo::PendingRemote<mojom::AudioStreamCreatorClient> client,
+    const media::AudioParameters& params,
+    uint32_t shared_memory_count) {
   resource_provider_->CreateAudioStream(std::move(client), params,
                                         shared_memory_count);
 }
@@ -893,10 +894,10 @@
 }
 
 void Session::ConnectToRemotingSource(
-    media::mojom::RemoterPtr remoter,
-    media::mojom::RemotingSourceRequest request) {
+    mojo::PendingRemote<media::mojom::Remoter> remoter,
+    mojo::PendingReceiver<media::mojom::RemotingSource> receiver) {
   resource_provider_->ConnectToRemotingSource(std::move(remoter),
-                                              std::move(request));
+                                              std::move(receiver));
 }
 
 void Session::RequestRemotingStreaming() {
diff --git a/components/mirroring/service/session.h b/components/mirroring/service/session.h
index b6a6a55..34a3543 100644
--- a/components/mirroring/service/session.h
+++ b/components/mirroring/service/session.h
@@ -23,6 +23,8 @@
 #include "media/cast/cast_environment.h"
 #include "media/cast/net/cast_transport_defines.h"
 #include "media/mojo/mojom/video_encode_accelerator.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 
 namespace media {
@@ -97,9 +99,10 @@
 
   // Creates an audio input stream through Audio Service. |client| will be
   // called after the stream is created.
-  void CreateAudioStream(mojom::AudioStreamCreatorClientPtr client,
-                         const media::AudioParameters& params,
-                         uint32_t shared_memory_count);
+  void CreateAudioStream(
+      mojo::PendingRemote<mojom::AudioStreamCreatorClient> client,
+      const media::AudioParameters& params,
+      uint32_t shared_memory_count);
 
   // Callback for CAPABILITIES_RESPONSE.
   void OnCapabilitiesResponse(const ReceiverResponse& response);
@@ -109,8 +112,9 @@
 
   // MediaRemoter::Client implementation.
   void ConnectToRemotingSource(
-      media::mojom::RemoterPtr remoter,
-      media::mojom::RemotingSourceRequest source_request) override;
+      mojo::PendingRemote<media::mojom::Remoter> remoter,
+      mojo::PendingReceiver<media::mojom::RemotingSource> source_receiver)
+      override;
   void RequestRemotingStreaming() override;
   void RestartMirroringStreaming() override;
 
diff --git a/components/mirroring/service/session_unittest.cc b/components/mirroring/service/session_unittest.cc
index 43680f8..525e6877 100644
--- a/components/mirroring/service/session_unittest.cc
+++ b/components/mirroring/service/session_unittest.cc
@@ -20,6 +20,8 @@
 #include "media/cast/test/utility/default_config.h"
 #include "media/cast/test/utility/net_utility.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/base/ip_address.h"
 #include "services/viz/public/cpp/gpu/gpu.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -44,11 +46,11 @@
 
 class MockRemotingSource final : public media::mojom::RemotingSource {
  public:
-  MockRemotingSource() : binding_(this) {}
+  MockRemotingSource() {}
   ~MockRemotingSource() override {}
 
-  void Bind(media::mojom::RemotingSourceRequest request) {
-    binding_.Bind(std::move(request));
+  void Bind(mojo::PendingReceiver<media::mojom::RemotingSource> receiver) {
+    receiver_.Bind(std::move(receiver));
   }
 
   MOCK_METHOD0(OnSinkGone, void());
@@ -62,7 +64,7 @@
   }
 
  private:
-  mojo::Binding<media::mojom::RemotingSource> binding_;
+  mojo::Receiver<media::mojom::RemotingSource> receiver_{this};
 };
 
 }  // namespace
@@ -126,17 +128,18 @@
     OnGetNetworkContext();
   }
 
-  void CreateAudioStream(mojom::AudioStreamCreatorClientPtr client,
-                         const media::AudioParameters& params,
-                         uint32_t total_segments) override {
+  void CreateAudioStream(
+      mojo::PendingRemote<mojom::AudioStreamCreatorClient> client,
+      const media::AudioParameters& params,
+      uint32_t total_segments) override {
     OnCreateAudioStream();
   }
 
   void ConnectToRemotingSource(
-      media::mojom::RemoterPtr remoter,
-      media::mojom::RemotingSourceRequest request) override {
-    remoter_ = std::move(remoter);
-    remoting_source_.Bind(std::move(request));
+      mojo::PendingRemote<media::mojom::Remoter> remoter,
+      mojo::PendingReceiver<media::mojom::RemotingSource> receiver) override {
+    remoter_.Bind(std::move(remoter));
+    remoting_source_.Bind(std::move(receiver));
     OnConnectToRemotingSource();
   }
 
@@ -341,7 +344,7 @@
   mojo::Binding<mojom::CastMessageChannel> outbound_channel_binding_;
   mojom::CastMessageChannelPtr inbound_channel_;
   SessionType session_type_ = SessionType::AUDIO_AND_VIDEO;
-  media::mojom::RemoterPtr remoter_;
+  mojo::Remote<media::mojom::Remoter> remoter_;
   MockRemotingSource remoting_source_;
   std::string cast_mode_;
   int32_t offer_sequence_number_ = -1;
diff --git a/components/payments/content/payment_instrument_unittest.cc b/components/payments/content/payment_instrument_unittest.cc
index 85d34190..9352064 100644
--- a/components/payments/content/payment_instrument_unittest.cc
+++ b/components/payments/content/payment_instrument_unittest.cc
@@ -22,19 +22,42 @@
 
 namespace payments {
 
-class PaymentInstrumentTest : public testing::Test,
-                              public PaymentRequestSpec::Observer {
+namespace {
+
+enum class RequiredPaymentOptions {
+  // None of the shipping address or contact information is required.
+  kNone,
+  // Shipping Address is required.
+  kShippingAddress,
+  // Payer's contact information(phone, name, email) is required.
+  kContactInformation,
+  // Payer's email is required.
+  kPayerEmail,
+  // Both contact information and shipping address are required.
+  kContactInformationAndShippingAddress,
+};
+
+}  // namespace
+
+class PaymentInstrumentTest
+    : public testing::TestWithParam<RequiredPaymentOptions>,
+      public PaymentRequestSpec::Observer {
  protected:
   PaymentInstrumentTest()
       : address_(autofill::test::GetFullProfile()),
         local_card_(autofill::test::GetCreditCard()),
-        billing_profiles_({&address_}) {
+        billing_profiles_({&address_}),
+        required_options_(GetParam()) {
     local_card_.set_billing_address_id(address_.guid());
     CreateSpec();
   }
 
   std::unique_ptr<ServiceWorkerPaymentInstrument>
-  CreateServiceWorkerPaymentInstrument(bool can_preselect) {
+  CreateServiceWorkerPaymentInstrument(bool can_preselect,
+                                       bool handles_shipping,
+                                       bool handles_name,
+                                       bool handles_phone,
+                                       bool handles_email) {
     constexpr int kBitmapDimension = 16;
 
     std::unique_ptr<content::StoredPaymentApp> stored_app =
@@ -47,6 +70,19 @@
       stored_app->icon->allocN32Pixels(kBitmapDimension, kBitmapDimension);
       stored_app->icon->eraseColor(SK_ColorRED);
     }
+    if (handles_shipping) {
+      stored_app->supported_delegations.shipping_address = true;
+    }
+    if (handles_name) {
+      stored_app->supported_delegations.payer_name = true;
+    }
+    if (handles_phone) {
+      stored_app->supported_delegations.payer_phone = true;
+    }
+    if (handles_email) {
+      stored_app->supported_delegations.payer_email = true;
+    }
+
     return std::make_unique<ServiceWorkerPaymentInstrument>(
         &browser_context_, GURL("https://testmerchant.com"),
         GURL("https://testmerchant.com/bobpay"), spec_.get(),
@@ -58,14 +94,38 @@
     return billing_profiles_;
   }
 
+  RequiredPaymentOptions required_options() const { return required_options_; }
+
  private:
   // PaymentRequestSpec::Observer
   void OnSpecUpdated() override {}
 
   void CreateSpec() {
     std::vector<mojom::PaymentMethodDataPtr> method_data;
+    mojom::PaymentOptionsPtr payment_options = mojom::PaymentOptions::New();
+    switch (required_options_) {
+      case RequiredPaymentOptions::kNone:
+        break;
+      case RequiredPaymentOptions::kShippingAddress:
+        payment_options->request_shipping = true;
+        break;
+      case RequiredPaymentOptions::kContactInformation:
+        payment_options->request_payer_name = true;
+        payment_options->request_payer_email = true;
+        payment_options->request_payer_phone = true;
+        break;
+      case RequiredPaymentOptions::kPayerEmail:
+        payment_options->request_payer_email = true;
+        break;
+      case RequiredPaymentOptions::kContactInformationAndShippingAddress:
+        payment_options->request_shipping = true;
+        payment_options->request_payer_name = true;
+        payment_options->request_payer_email = true;
+        payment_options->request_payer_phone = true;
+        break;
+    }
     spec_ = std::make_unique<PaymentRequestSpec>(
-        mojom::PaymentOptions::New(), mojom::PaymentDetails::New(),
+        std::move(payment_options), mojom::PaymentDetails::New(),
         std::move(method_data), this, "en-US");
   }
 
@@ -76,12 +136,23 @@
   std::vector<autofill::AutofillProfile*> billing_profiles_;
   MockPaymentRequestDelegate delegate_;
   MockIdentityObserver identity_observer_;
+  RequiredPaymentOptions required_options_;
   std::unique_ptr<PaymentRequestSpec> spec_;
 
   DISALLOW_COPY_AND_ASSIGN(PaymentInstrumentTest);
 };
 
-TEST_F(PaymentInstrumentTest, SortInstruments) {
+INSTANTIATE_TEST_SUITE_P(
+    ,
+    PaymentInstrumentTest,
+    ::testing::Values(
+        RequiredPaymentOptions::kNone,
+        RequiredPaymentOptions::kShippingAddress,
+        RequiredPaymentOptions::kContactInformation,
+        RequiredPaymentOptions::kPayerEmail,
+        RequiredPaymentOptions::kContactInformationAndShippingAddress));
+
+TEST_P(PaymentInstrumentTest, SortInstruments) {
   std::vector<PaymentInstrument*> instruments;
   // Add a complete instrument with mismatching type.
   autofill::CreditCard complete_dismatching_card = local_credit_card();
@@ -109,13 +180,18 @@
 
   // Add a non-preselectable sw based payment instrument.
   std::unique_ptr<ServiceWorkerPaymentInstrument>
-      non_preselectable_sw_instrument =
-          CreateServiceWorkerPaymentInstrument(false);
+      non_preselectable_sw_instrument = CreateServiceWorkerPaymentInstrument(
+          false /* = can_preselect */, false /* = handles_shipping */,
+          false /* = handles_name */, false /* = handles_phone */,
+          false /* = handles_email */);
   instruments.push_back(non_preselectable_sw_instrument.get());
 
   // Add a preselectable sw based payment instrument.
   std::unique_ptr<ServiceWorkerPaymentInstrument> preselectable_sw_instrument =
-      CreateServiceWorkerPaymentInstrument(true);
+      CreateServiceWorkerPaymentInstrument(
+          true /* = can_preselect */, false /* = handles_shipping */,
+          false /* = handles_name */, false /* = handles_phone */,
+          false /* = handles_email */);
   instruments.push_back(preselectable_sw_instrument.get());
 
   // Add an instrument with no name.
@@ -159,6 +235,7 @@
   size_t i = 0;
   EXPECT_EQ(instruments[i++], preselectable_sw_instrument.get());
   EXPECT_EQ(instruments[i++], non_preselectable_sw_instrument.get());
+
   // Autfill instruments (credit cards) come after sw instruments.
   EXPECT_EQ(instruments[i++], &complete_frequently_used_cc_instrument);
   EXPECT_EQ(instruments[i++], &complete_matching_cc_instrument);
@@ -169,4 +246,105 @@
   EXPECT_EQ(instruments[i++], &cc_instrument_with_no_number);
 }
 
+TEST_P(PaymentInstrumentTest, SortInstrumentsBasedOnSupportedDelegations) {
+  std::vector<PaymentInstrument*> instruments;
+  // Add a preselectable sw based payment instrument which does not support
+  // shipping or contact delegation.
+  std::unique_ptr<ServiceWorkerPaymentInstrument> does_not_support_delegations =
+      CreateServiceWorkerPaymentInstrument(
+          true /* = can_preselect */, false /* = handles_shipping */,
+          false /* = handles_name */, false /* = handles_phone */,
+          false /* = handles_email */);
+  instruments.push_back(does_not_support_delegations.get());
+
+  // Add a preselectable sw based payment instrument which handles shipping.
+  std::unique_ptr<ServiceWorkerPaymentInstrument> handles_shipping_address =
+      CreateServiceWorkerPaymentInstrument(
+          true /* = can_preselect */, true /* = handles_shipping */,
+          false /* = handles_name */, false /* = handles_phone */,
+          false /* = handles_email */);
+  instruments.push_back(handles_shipping_address.get());
+
+  // Add a preselectable sw based payment instrument which handles payer's
+  // email.
+  std::unique_ptr<ServiceWorkerPaymentInstrument> handles_payer_email =
+      CreateServiceWorkerPaymentInstrument(
+          true /* = can_preselect */, false /* = handles_shipping */,
+          false /* = handles_name */, false /* = handles_phone */,
+          true /* = handles_email */);
+  instruments.push_back(handles_payer_email.get());
+
+  // Add a preselectable sw based payment instrument which handles contact
+  // information.
+  std::unique_ptr<ServiceWorkerPaymentInstrument> handles_contact_info =
+      CreateServiceWorkerPaymentInstrument(
+          true /* = can_preselect */, false /* = handles_shipping */,
+          true /* = handles_name */, true /* = handles_phone */,
+          true /* = handles_email */);
+  instruments.push_back(handles_contact_info.get());
+
+  // Add a preselectable sw based payment instrument which handles both shipping
+  // address and contact information.
+  std::unique_ptr<ServiceWorkerPaymentInstrument> handles_shipping_and_contact =
+      CreateServiceWorkerPaymentInstrument(
+          true /* = can_preselect */, true /* = handles_shipping */,
+          true /* = handles_name */, true /* = handles_phone */,
+          true /* = handles_email */);
+  instruments.push_back(handles_shipping_and_contact.get());
+
+  PaymentInstrument::SortInstruments(&instruments);
+  size_t i = 0;
+
+  switch (required_options()) {
+    case RequiredPaymentOptions::kNone: {
+      // When no payemnt option is required the order of the payment instruments
+      // does not change.
+      EXPECT_EQ(instruments[i++], does_not_support_delegations.get());
+      EXPECT_EQ(instruments[i++], handles_shipping_address.get());
+      EXPECT_EQ(instruments[i++], handles_payer_email.get());
+      EXPECT_EQ(instruments[i++], handles_contact_info.get());
+      EXPECT_EQ(instruments[i++], handles_shipping_and_contact.get());
+      break;
+    }
+    case RequiredPaymentOptions::kShippingAddress: {
+      // Instruments that handle shipping address come first.
+      EXPECT_EQ(instruments[i++], handles_shipping_address.get());
+      EXPECT_EQ(instruments[i++], handles_shipping_and_contact.get());
+      // The order is unchanged for instruments that do not handle shipping.
+      EXPECT_EQ(instruments[i++], does_not_support_delegations.get());
+      EXPECT_EQ(instruments[i++], handles_payer_email.get());
+      EXPECT_EQ(instruments[i++], handles_contact_info.get());
+      break;
+    }
+    case RequiredPaymentOptions::kContactInformation: {
+      // Instruments that handle all required contact information come first.
+      EXPECT_EQ(instruments[i++], handles_contact_info.get());
+      EXPECT_EQ(instruments[i++], handles_shipping_and_contact.get());
+      // The instrument that partially handles contact information comes next.
+      EXPECT_EQ(instruments[i++], handles_payer_email.get());
+      // The order for instruments that do not handle contact information is not
+      // changed.
+      EXPECT_EQ(instruments[i++], does_not_support_delegations.get());
+      EXPECT_EQ(instruments[i++], handles_shipping_address.get());
+      break;
+    }
+    case RequiredPaymentOptions::kPayerEmail: {
+      EXPECT_EQ(instruments[i++], handles_payer_email.get());
+      EXPECT_EQ(instruments[i++], handles_contact_info.get());
+      EXPECT_EQ(instruments[i++], handles_shipping_and_contact.get());
+      EXPECT_EQ(instruments[i++], does_not_support_delegations.get());
+      EXPECT_EQ(instruments[i++], handles_shipping_address.get());
+      break;
+    }
+    case RequiredPaymentOptions::kContactInformationAndShippingAddress: {
+      EXPECT_EQ(instruments[i++], handles_shipping_and_contact.get());
+      EXPECT_EQ(instruments[i++], handles_shipping_address.get());
+      EXPECT_EQ(instruments[i++], handles_contact_info.get());
+      EXPECT_EQ(instruments[i++], handles_payer_email.get());
+      EXPECT_EQ(instruments[i++], does_not_support_delegations.get());
+      break;
+    }
+  }
+}
+
 }  // namespace payments
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc
index 72bab9b..d69d1ca 100644
--- a/components/payments/content/payment_request.cc
+++ b/components/payments/content/payment_request.cc
@@ -537,8 +537,14 @@
       is_show_user_gesture_ && state()->IsInitialized() &&
       spec()->IsInitialized() && state()->available_instruments().size() == 1 &&
       spec()->stringified_method_data().size() == 1 &&
-      !spec()->request_shipping() && !spec()->request_payer_name() &&
-      !spec()->request_payer_phone() && !spec()->request_payer_email();
+      (!spec()->request_shipping() ||
+       state()->available_instruments().front()->HandlesShippingAddress()) &&
+      (!spec()->request_payer_name() ||
+       state()->available_instruments().front()->HandlesPayerName()) &&
+      (!spec()->request_payer_phone() ||
+       state()->available_instruments().front()->HandlesPayerPhone()) &&
+      (!spec()->request_payer_email() ||
+       state()->available_instruments().front()->HandlesPayerEmail());
   if (skipped_payment_request_ui_) {
     DCHECK(state()->IsInitialized() && spec()->IsInitialized());
     journey_logger_.SetEventOccurred(JourneyLogger::EVENT_SKIPPED_SHOW);
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc
index 9843380b..9987048 100644
--- a/components/payments/content/payment_request_state.cc
+++ b/components/payments/content/payment_request_state.cc
@@ -330,19 +330,18 @@
 }
 
 void PaymentRequestState::RecordUseStats() {
-  if (spec_->request_shipping()) {
+  if (ShouldShowShippingSection()) {
     DCHECK(selected_shipping_profile_);
     personal_data_manager_->RecordUseOf(*selected_shipping_profile_);
   }
 
-  if (spec_->request_payer_name() || spec_->request_payer_email() ||
-      spec_->request_payer_phone()) {
+  if (ShouldShowContactSection()) {
     DCHECK(selected_contact_profile_);
 
     // If the same address was used for both contact and shipping, the stats
     // should only be updated once.
-    if (!spec_->request_shipping() || (selected_shipping_profile_->guid() !=
-                                       selected_contact_profile_->guid())) {
+    if (!ShouldShowShippingSection() || (selected_shipping_profile_->guid() !=
+                                         selected_contact_profile_->guid())) {
       personal_data_manager_->RecordUseOf(*selected_contact_profile_);
     }
   }
@@ -534,6 +533,31 @@
   UpdateIsReadyToPayAndNotifyObservers();
 }
 
+bool PaymentRequestState::ShouldShowShippingSection() const {
+  if (!spec_->request_shipping())
+    return false;
+
+  return selected_instrument_ ? !selected_instrument_->HandlesShippingAddress()
+                              : true;
+}
+
+bool PaymentRequestState::ShouldShowContactSection() const {
+  if (spec_->request_payer_name() &&
+      (!selected_instrument_ || !selected_instrument_->HandlesPayerName())) {
+    return true;
+  }
+  if (spec_->request_payer_email() &&
+      (!selected_instrument_ || !selected_instrument_->HandlesPayerEmail())) {
+    return true;
+  }
+  if (spec_->request_payer_phone() &&
+      (!selected_instrument_ || !selected_instrument_->HandlesPayerPhone())) {
+    return true;
+  }
+
+  return false;
+}
+
 base::WeakPtr<PaymentRequestState> PaymentRequestState::AsWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
 }
@@ -561,8 +585,7 @@
 
   // Set the number of suggestions shown for the sections requested by the
   // merchant.
-  if (spec_->request_payer_name() || spec_->request_payer_phone() ||
-      spec_->request_payer_email()) {
+  if (ShouldShowContactSection()) {
     bool has_complete_contact =
         contact_profiles_.empty()
             ? false
@@ -572,7 +595,7 @@
         JourneyLogger::Section::SECTION_CONTACT_INFO, contact_profiles_.size(),
         has_complete_contact);
   }
-  if (spec_->request_shipping()) {
+  if (ShouldShowShippingSection()) {
     bool has_complete_shipping =
         shipping_profiles_.empty()
             ? false
@@ -668,13 +691,18 @@
   if (is_waiting_for_merchant_validation_)
     return false;
 
-  if (!profile_comparator()->IsShippingComplete(selected_shipping_profile_))
+  if (ShouldShowShippingSection() &&
+      (!spec_->selected_shipping_option() ||
+       !profile_comparator()->IsShippingComplete(selected_shipping_profile_))) {
     return false;
+  }
 
-  if (spec_->request_shipping() && !spec_->selected_shipping_option())
+  if (ShouldShowContactSection() &&
+      !profile_comparator()->IsContactInfoComplete(selected_contact_profile_)) {
     return false;
+  }
 
-  return profile_comparator()->IsContactInfoComplete(selected_contact_profile_);
+  return true;
 }
 
 void PaymentRequestState::OnAddressNormalized(
diff --git a/components/payments/content/payment_request_state.h b/components/payments/content/payment_request_state.h
index 2fd3518..94c80d0 100644
--- a/components/payments/content/payment_request_state.h
+++ b/components/payments/content/payment_request_state.h
@@ -264,6 +264,14 @@
   // Selects the default shipping address.
   void SelectDefaultShippingAddressAndNotifyObservers();
 
+  // Returns true when shipping address is required and the selected instrument
+  // (if any) does not support shipping address delegation.
+  bool ShouldShowShippingSection() const;
+
+  // Returns true when payer name/phone/email is required and the selected
+  // instrument (if any) does not support required contact info delegation.
+  bool ShouldShowContactSection() const;
+
   base::WeakPtr<PaymentRequestState> AsWeakPtr();
 
   void set_is_show_user_gesture(bool is_show_user_gesture) {
diff --git a/components/payments/content/service_worker_payment_instrument.cc b/components/payments/content/service_worker_payment_instrument.cc
index c125666..68842229 100644
--- a/components/payments/content/service_worker_payment_instrument.cc
+++ b/components/payments/content/service_worker_payment_instrument.cc
@@ -458,4 +458,40 @@
   return icon_image_;
 }
 
+bool ServiceWorkerPaymentInstrument::HandlesShippingAddress() const {
+  if (!spec_->request_shipping())
+    return false;
+
+  return stored_payment_app_info_
+             ? stored_payment_app_info_->supported_delegations.shipping_address
+             : false;
+}
+
+bool ServiceWorkerPaymentInstrument::HandlesPayerName() const {
+  if (!spec_->request_payer_name())
+    return false;
+
+  return stored_payment_app_info_
+             ? stored_payment_app_info_->supported_delegations.payer_name
+             : false;
+}
+
+bool ServiceWorkerPaymentInstrument::HandlesPayerEmail() const {
+  if (!spec_->request_payer_email())
+    return false;
+
+  return stored_payment_app_info_
+             ? stored_payment_app_info_->supported_delegations.payer_email
+             : false;
+}
+
+bool ServiceWorkerPaymentInstrument::HandlesPayerPhone() const {
+  if (!spec_->request_payer_phone())
+    return false;
+
+  return stored_payment_app_info_
+             ? stored_payment_app_info_->supported_delegations.payer_phone
+             : false;
+}
+
 }  // namespace payments
diff --git a/components/payments/content/service_worker_payment_instrument.h b/components/payments/content/service_worker_payment_instrument.h
index d288913..d71a942c9 100644
--- a/components/payments/content/service_worker_payment_instrument.h
+++ b/components/payments/content/service_worker_payment_instrument.h
@@ -109,6 +109,10 @@
       bool* is_valid) const override;
   base::WeakPtr<PaymentInstrument> AsWeakPtr() override;
   gfx::ImageSkia icon_image_skia() const override;
+  bool HandlesShippingAddress() const override;
+  bool HandlesPayerName() const override;
+  bool HandlesPayerEmail() const override;
+  bool HandlesPayerPhone() const override;
 
   void set_payment_handler_host(
       mojo::PendingRemote<mojom::PaymentHandlerHost> payment_handler_host) {
diff --git a/components/payments/core/autofill_payment_instrument.cc b/components/payments/core/autofill_payment_instrument.cc
index 8d94ac3..538b102 100644
--- a/components/payments/core/autofill_payment_instrument.cc
+++ b/components/payments/core/autofill_payment_instrument.cc
@@ -251,4 +251,20 @@
     GenerateBasicCardResponse();
 }
 
+bool AutofillPaymentInstrument::HandlesShippingAddress() const {
+  return false;
+}
+
+bool AutofillPaymentInstrument::HandlesPayerName() const {
+  return false;
+}
+
+bool AutofillPaymentInstrument::HandlesPayerEmail() const {
+  return false;
+}
+
+bool AutofillPaymentInstrument::HandlesPayerPhone() const {
+  return false;
+}
+
 }  // namespace payments
diff --git a/components/payments/core/autofill_payment_instrument.h b/components/payments/core/autofill_payment_instrument.h
index 3c78957f..3104f9f4 100644
--- a/components/payments/core/autofill_payment_instrument.h
+++ b/components/payments/core/autofill_payment_instrument.h
@@ -60,6 +60,10 @@
       const std::string& payment_method_identifier,
       bool* is_valid) const override;
   base::WeakPtr<PaymentInstrument> AsWeakPtr() override;
+  bool HandlesShippingAddress() const override;
+  bool HandlesPayerName() const override;
+  bool HandlesPayerEmail() const override;
+  bool HandlesPayerPhone() const override;
 
   // autofill::payments::FullCardRequest::ResultDelegate:
   void OnFullCardRequestSucceeded(
diff --git a/components/payments/core/journey_logger.cc b/components/payments/core/journey_logger.cc
index ea679d9..64546d9d 100644
--- a/components/payments/core/journey_logger.cc
+++ b/components/payments/core/journey_logger.cc
@@ -481,15 +481,6 @@
   if (events_ & EVENT_SKIPPED_SHOW) {
     // Built in autofill payment handler for basic card should not skip UI show.
     DCHECK(!(events_ & EVENT_SELECTED_CREDIT_CARD));
-    // Payment sheet should not get skipped when any of the following info is
-    // required, unless skip-to-gpay is enabled. Checking the feature flag here
-    // may mess up the Finch result, so using EVENT_REQUEST_METHOD_GOOGLE as a
-    // proxy.
-    bool gpay_requested = events_ & EVENT_REQUEST_METHOD_GOOGLE;
-    DCHECK(!(events_ & EVENT_REQUEST_SHIPPING) || gpay_requested);
-    DCHECK(!(events_ & EVENT_REQUEST_PAYER_NAME) || gpay_requested);
-    DCHECK(!(events_ & EVENT_REQUEST_PAYER_EMAIL) || gpay_requested);
-    DCHECK(!(events_ & EVENT_REQUEST_PAYER_PHONE) || gpay_requested);
   }
 
   // Check that the two bits are not set at the same time.
diff --git a/components/payments/core/payment_instrument.cc b/components/payments/core/payment_instrument.cc
index 3c8ce8c..6105827a 100644
--- a/components/payments/core/payment_instrument.cc
+++ b/components/payments/core/payment_instrument.cc
@@ -72,6 +72,36 @@
             autofill::AutofillClock::Now());
   }
 
+  // SW based payment instruments are sorted based on whether they will handle
+  // shipping delegation or not (i.e. shipping address is requested and the
+  // instrument supports the delegation.).
+  if (HandlesShippingAddress() != other.HandlesShippingAddress())
+    return HandlesShippingAddress();
+
+  // SW based payment instruments are sorted based on the number of the contact
+  // field delegations that they will handle (i.e. number of contact fields
+  // which are requested and the instruments support their delegations.)
+  int supported_contact_delegations_num = 0;
+  if (HandlesPayerEmail())
+    supported_contact_delegations_num++;
+  if (HandlesPayerName())
+    supported_contact_delegations_num++;
+  if (HandlesPayerPhone())
+    supported_contact_delegations_num++;
+
+  int other_supported_contact_delegations_num = 0;
+  if (other.HandlesPayerEmail())
+    other_supported_contact_delegations_num++;
+  if (other.HandlesPayerName())
+    other_supported_contact_delegations_num++;
+  if (other.HandlesPayerPhone())
+    other_supported_contact_delegations_num++;
+
+  int contact_delegations_diff = supported_contact_delegations_num -
+                                 other_supported_contact_delegations_num;
+  if (contact_delegations_diff != 0)
+    return contact_delegations_diff > 0;
+
   // SW based payment instruments are sorted based on whether they can be
   // pre-selected or not. Note that autofill based instruments are already
   // sorted by CanPreselect() since they are sorted by completeness and type
diff --git a/components/payments/core/payment_instrument.h b/components/payments/core/payment_instrument.h
index 77504b69..bba4752 100644
--- a/components/payments/core/payment_instrument.h
+++ b/components/payments/core/payment_instrument.h
@@ -98,6 +98,14 @@
   // Returns a WeakPtr to this payment instrument.
   virtual base::WeakPtr<PaymentInstrument> AsWeakPtr() = 0;
 
+  // Returns true if this payment instrument can collect and return the required
+  // information. This is used to show/hide shipping/contact sections in payment
+  // sheet view depending on the selected instrument.
+  virtual bool HandlesShippingAddress() const = 0;
+  virtual bool HandlesPayerName() const = 0;
+  virtual bool HandlesPayerEmail() const = 0;
+  virtual bool HandlesPayerPhone() const = 0;
+
   // Sorts the instruments using the overloaded < operator.
   static void SortInstruments(
       std::vector<std::unique_ptr<PaymentInstrument>>* instruments);
diff --git a/components/test/data/payments/payment_handler.js b/components/test/data/payments/payment_handler.js
index f14b9b969..9c7ddfdd 100644
--- a/components/test/data/payments/payment_handler.js
+++ b/components/test/data/payments/payment_handler.js
@@ -33,6 +33,33 @@
 }
 
 /**
+ * Delegates handling of the provided options to the payment handler.
+ * @param {Array<string>} delegations The list of payment options to delegate.
+ * @return {string} The 'success' or error message.
+ */
+async function enableDelegations(delegations) { // eslint-disable-line no-unused-vars, max-len
+  try {
+    await navigator.serviceWorker.ready;
+    let registration =
+        await navigator.serviceWorker.getRegistration(swSrcUrl);
+    if (!registration) {
+      return 'The payment handler is not installed.';
+    }
+    if (!registration.paymentManager) {
+      return 'PaymentManager API not found.';
+    }
+    if (!registration.paymentManager.enableDelegations) {
+      return 'PaymentManager does not support enableDelegations method';
+    }
+
+    await registration.paymentManager.enableDelegations(delegations);
+    return 'success';
+  } catch (e) {
+    return e.toString();
+  }
+}
+
+/**
  * Launches the payment handler.
  */
 async function launch() { // eslint-disable-line no-unused-vars
@@ -47,3 +74,45 @@
     return e.toString();
   }
 }
+
+/**
+ * Creates a payment request with required information and calls request.show()
+ * to invoke payment sheet UI. To ensure that UI gets shown two payment methods
+ * are supported: One url-based and one 'basic-card'.
+ * @param {Object} options The list of requested paymentOptions.
+ * @return {string} The 'success' or error message.
+ */
+function paymentRequestWithOptions(options) { // eslint-disable-line no-unused-vars, max-len
+  try {
+    const request = new PaymentRequest([{
+          supportedMethods: methodName,
+        },
+        {
+          supportedMethods: 'basic-card',
+        },
+      ], {
+        total: {
+          label: 'Total',
+          amount: {
+            currency: 'USD',
+            value: '0.01',
+          },
+        },
+        shippingOptions: [{
+          id: 'freeShippingOption',
+          label: 'Free global shipping',
+          amount: {
+            currency: 'USD',
+            value: '0',
+          },
+          selected: true,
+        }],
+      },
+      options);
+
+    request.show();
+    return 'success';
+  } catch (e) {
+    return e.toString();
+  }
+}
diff --git a/components/viz/host/gpu_client.cc b/components/viz/host/gpu_client.cc
index 3f213deae..2f40ee92 100644
--- a/components/viz/host/gpu_client.cc
+++ b/components/viz/host/gpu_client.cc
@@ -32,26 +32,26 @@
       client_tracing_id_(client_tracing_id),
       task_runner_(std::move(task_runner)) {
   DCHECK(delegate_);
-  gpu_bindings_.set_connection_error_handler(
+  gpu_receivers_.set_disconnect_handler(
       base::BindRepeating(&GpuClient::OnError, base::Unretained(this),
                           ErrorReason::kConnectionLost));
 }
 
 GpuClient::~GpuClient() {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  gpu_bindings_.CloseAllBindings();
+  gpu_receivers_.Clear();
   OnError(ErrorReason::kInDestructor);
 }
 
-void GpuClient::Add(mojom::GpuRequest request) {
+void GpuClient::Add(mojo::PendingReceiver<mojom::Gpu> receiver) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  gpu_bindings_.AddBinding(this, std::move(request));
+  gpu_receivers_.Add(this, std::move(receiver));
 }
 
 void GpuClient::OnError(ErrorReason reason) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
   ClearCallback();
-  if (gpu_bindings_.empty() && delegate_) {
+  if (gpu_receivers_.empty() && delegate_) {
     if (auto* gpu_memory_buffer_manager =
             delegate_->GetGpuMemoryBufferManager()) {
       gpu_memory_buffer_manager->DestroyAllGpuMemoryBufferForClient(client_id_);
diff --git a/components/viz/host/gpu_client.h b/components/viz/host/gpu_client.h
index 54b27c72..a60e6ac 100644
--- a/components/viz/host/gpu_client.h
+++ b/components/viz/host/gpu_client.h
@@ -31,7 +31,7 @@
   ~GpuClient() override;
 
   // This needs to be run on the thread associated with |task_runner_|.
-  void Add(mojom::GpuRequest request);
+  void Add(mojo::PendingReceiver<mojom::Gpu> receiver);
 
   void PreEstablishGpuChannel();
 
@@ -86,7 +86,7 @@
   const uint64_t client_tracing_id_;
   mojo::ReceiverSet<mojom::GpuMemoryBufferFactory>
       gpu_memory_buffer_factory_receivers_;
-  mojo::BindingSet<mojom::Gpu> gpu_bindings_;
+  mojo::ReceiverSet<mojom::Gpu> gpu_receivers_;
   bool gpu_channel_requested_ = false;
   EstablishGpuChannelCallback callback_;
   mojo::ScopedMessagePipeHandle channel_handle_;
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index b9fde8e..9e3d6aa 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -621,15 +621,18 @@
   auto it = root_sink_map_.find(root_frame_sink_id);
 
   DCHECK(it != root_sink_map_.end());
-  DCHECK(cached_back_buffers_.find(cache_id) == cached_back_buffers_.end());
+  // TODO(khushalsagar) : Temp CHECKs for debugging. See crbug.com/992626.
+  CHECK(cached_back_buffers_.find(cache_id) == cached_back_buffers_.end());
 
   cached_back_buffers_[cache_id] = it->second->GetCacheBackBufferCb();
+  CHECK(!cached_back_buffers_[cache_id].is_null());
 }
 
 void FrameSinkManagerImpl::EvictBackBuffer(uint32_t cache_id,
                                            EvictBackBufferCallback callback) {
   auto it = cached_back_buffers_.find(cache_id);
-  DCHECK(it != cached_back_buffers_.end());
+  // TODO(khushalsagar) : Temp CHECKs for debugging. See crbug.com/992626.
+  CHECK(it != cached_back_buffers_.end());
 
   it->second.RunAndReset();
   cached_back_buffers_.erase(it);
diff --git a/components/viz/test/test_context_support.cc b/components/viz/test/test_context_support.cc
index 6267c35..173cc4d 100644
--- a/components/viz/test/test_context_support.cc
+++ b/components/viz/test/test_context_support.cc
@@ -131,9 +131,14 @@
   NOTIMPLEMENTED();
   return 0;
 }
+bool TestContextSupport::IsJpegDecodeAccelerationSupported() const {
+  return false;
+}
+bool TestContextSupport::IsWebPDecodeAccelerationSupported() const {
+  return false;
+}
 bool TestContextSupport::CanDecodeWithHardwareAcceleration(
     base::span<const uint8_t> encoded_data) const {
-  NOTIMPLEMENTED();
   return false;
 }
 
diff --git a/components/viz/test/test_context_support.h b/components/viz/test/test_context_support.h
index fd3a6d9..8bc6fe1 100644
--- a/components/viz/test/test_context_support.h
+++ b/components/viz/test/test_context_support.h
@@ -77,6 +77,8 @@
   void DeleteTransferCacheEntry(uint32_t entry_type,
                                 uint32_t entry_id) override;
   unsigned int GetTransferBufferFreeSize() const override;
+  bool IsJpegDecodeAccelerationSupported() const override;
+  bool IsWebPDecodeAccelerationSupported() const override;
   bool CanDecodeWithHardwareAcceleration(
       base::span<const uint8_t> encoded_data) const override;
   bool HasGrContextSupport() const override;
diff --git a/content/app_shim_remote_cocoa/ns_view_bridge_factory_impl.mm b/content/app_shim_remote_cocoa/ns_view_bridge_factory_impl.mm
index 85f739a..9743a05 100644
--- a/content/app_shim_remote_cocoa/ns_view_bridge_factory_impl.mm
+++ b/content/app_shim_remote_cocoa/ns_view_bridge_factory_impl.mm
@@ -17,6 +17,8 @@
 #include "content/common/render_widget_host_ns_view.mojom.h"
 #include "content/common/web_contents_ns_view_bridge.mojom.h"
 #include "content/public/browser/native_web_keyboard_event.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #include "ui/base/cocoa/remote_accessibility_api.h"
@@ -30,20 +32,20 @@
     : public RenderWidgetHostNSViewHostHelper {
  public:
   explicit RenderWidgetHostNSViewBridgeOwner(
-      mojom::RenderWidgetHostNSViewHostAssociatedPtr client,
+      mojo::PendingAssociatedRemote<mojom::RenderWidgetHostNSViewHost> client,
       mojo::PendingAssociatedReceiver<mojom::RenderWidgetHostNSView>
           bridge_receiver)
       : host_(std::move(client)) {
     bridge_ = std::make_unique<remote_cocoa::RenderWidgetHostNSViewBridge>(
         host_.get(), this);
     bridge_->BindReceiver(std::move(bridge_receiver));
-    host_.set_connection_error_handler(
-        base::BindOnce(&RenderWidgetHostNSViewBridgeOwner::OnConnectionError,
+    host_.set_disconnect_handler(
+        base::BindOnce(&RenderWidgetHostNSViewBridgeOwner::OnMojoDisconnect,
                        base::Unretained(this)));
   }
 
  private:
-  void OnConnectionError() { delete this; }
+  void OnMojoDisconnect() { delete this; }
 
   std::unique_ptr<content::InputEvent> TranslateEvent(
       const blink::WebInputEvent& web_event) {
@@ -120,7 +122,7 @@
     host_->SmartMagnify(TranslateEvent(web_event));
   }
 
-  mojom::RenderWidgetHostNSViewHostAssociatedPtr host_;
+  mojo::AssociatedRemote<mojom::RenderWidgetHostNSViewHost> host_;
   std::unique_ptr<RenderWidgetHostNSViewBridge> bridge_;
   base::scoped_nsobject<NSAccessibilityRemoteUIElement>
       remote_accessibility_element_;
@@ -136,9 +138,8 @@
   // and mojom::RenderWidgetHostNSView private interfaces.
   // TODO(ccameron): Remove the need for this cast.
   // https://crbug.com/888290
-  mojom::RenderWidgetHostNSViewHostAssociatedPtr host(
-      mojo::AssociatedInterfacePtrInfo<mojom::RenderWidgetHostNSViewHost>(
-          std::move(host_handle), 0));
+  mojo::PendingAssociatedRemote<mojom::RenderWidgetHostNSViewHost> host(
+      std::move(host_handle), 0);
 
   // Create a RenderWidgetHostNSViewBridgeOwner. The resulting object will be
   // destroyed when its underlying pipe is closed.
diff --git a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.h b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.h
index 6f73679..9ca50d2 100644
--- a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.h
+++ b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.h
@@ -16,6 +16,7 @@
 #include "content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h"
 #include "content/common/edit_command.h"
 #include "content/common/render_widget_host_ns_view.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #import "ui/base/cocoa/command_dispatcher.h"
 #import "ui/base/cocoa/tool_tip_base_view.h"
 #include "ui/base/ime/ime_text_span.h"
@@ -76,7 +77,7 @@
 
   // Dummy host and host helper that are always valid (see above comments
   // about host_).
-  remote_cocoa::mojom::RenderWidgetHostNSViewHostPtr dummyHost_;
+  mojo::Remote<remote_cocoa::mojom::RenderWidgetHostNSViewHost> dummyHost_;
   std::unique_ptr<remote_cocoa::RenderWidgetHostNSViewHostHelper>
       dummyHostHelper_;
 
diff --git a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
index dc48d36..d8de080 100644
--- a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
+++ b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
@@ -582,8 +582,7 @@
 - (void)setHostDisconnected {
   // Set the host to be an abandoned message pipe, and set the hostHelper
   // to forward messages to that host.
-  remote_cocoa::mojom::RenderWidgetHostNSViewHostRequest dummyHostRequest =
-      mojo::MakeRequest(&dummyHost_);
+  ignore_result(dummyHost_.BindNewPipeAndPassReceiver());
   dummyHostHelper_ = std::make_unique<DummyHostHelper>();
   host_ = dummyHost_.get();
   hostHelper_ = dummyHostHelper_.get();
@@ -599,7 +598,7 @@
 }
 
 - (bool)hostIsDisconnected {
-  return host_ == dummyHost_.get();
+  return host_ == (dummyHost_.is_bound() ? dummyHost_.get() : nullptr);
 }
 
 - (void)setShowingContextMenu:(BOOL)showing {
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 4581ce6e..b6e15778 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -2440,10 +2440,6 @@
       # Similar to the bug below, there should be an API to let the embedder
       # control this.
       defines += [ "DISABLE_OVERSCROLL" ]
-    } else {
-      # TODO(crbug.com/986346): this define should not be required once debug URL
-      # triggering has been generalized.
-      defines += [ "ENABLE_ADDRESS_BAR" ]
     }
   } else {
     # Not Android.
diff --git a/content/browser/blob_storage/chrome_blob_storage_context.cc b/content/browser/blob_storage/chrome_blob_storage_context.cc
index 0d5a04d..a70eb15 100644
--- a/content/browser/blob_storage/chrome_blob_storage_context.cc
+++ b/content/browser/blob_storage/chrome_blob_storage_context.cc
@@ -229,11 +229,11 @@
 }
 
 // static
-blink::mojom::BlobPtr ChromeBlobStorageContext::GetBlobPtr(
+mojo::PendingRemote<blink::mojom::Blob> ChromeBlobStorageContext::GetBlobRemote(
     BrowserContext* browser_context,
     const std::string& uuid) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  blink::mojom::BlobPtr blob_ptr;
+  mojo::PendingRemote<blink::mojom::Blob> blob_remote;
   base::PostTask(
       FROM_HERE, {BrowserThread::IO},
       base::BindOnce(
@@ -244,9 +244,9 @@
             if (handle)
               storage::BlobImpl::Create(std::move(handle), std::move(receiver));
           },
-          base::WrapRefCounted(GetFor(browser_context)), MakeRequest(&blob_ptr),
-          uuid));
-  return blob_ptr;
+          base::WrapRefCounted(GetFor(browser_context)),
+          blob_remote.InitWithNewPipeAndPassReceiver(), uuid));
+  return blob_remote;
 }
 
 ChromeBlobStorageContext::~ChromeBlobStorageContext() = default;
diff --git a/content/browser/blob_storage/chrome_blob_storage_context.h b/content/browser/blob_storage/chrome_blob_storage_context.h
index 19457bb6..8182634c 100644
--- a/content/browser/blob_storage/chrome_blob_storage_context.h
+++ b/content/browser/blob_storage/chrome_blob_storage_context.h
@@ -16,6 +16,7 @@
 #include "base/sequenced_task_runner_helpers.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_thread.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "storage/browser/blob/blob_data_handle.h"
 #include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h"
@@ -89,8 +90,9 @@
       const GURL& url);
 
   // Must be called on the UI thread.
-  static blink::mojom::BlobPtr GetBlobPtr(BrowserContext* browser_context,
-                                          const std::string& uuid);
+  static mojo::PendingRemote<blink::mojom::Blob> GetBlobRemote(
+      BrowserContext* browser_context,
+      const std::string& uuid);
 
  protected:
   virtual ~ChromeBlobStorageContext();
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index 9e5b738..220d0a43 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -498,11 +498,11 @@
 }
 
 // static
-blink::mojom::BlobPtr BrowserContext::GetBlobPtr(
+mojo::PendingRemote<blink::mojom::Blob> BrowserContext::GetBlobRemote(
     BrowserContext* browser_context,
     const std::string& uuid) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  return ChromeBlobStorageContext::GetBlobPtr(browser_context, uuid);
+  return ChromeBlobStorageContext::GetBlobRemote(browser_context, uuid);
 }
 
 // static
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 286e70f..38ef9cc 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -175,11 +175,9 @@
       bool transient,
       const std::vector<download::DownloadItem::ReceivedSlice>& received_slices)
       override {
-    int auto_resume_count = 0;
-    if (base::FeatureList::IsEnabled(
-            download::features::kDownloadDBForNewDownloads)) {
-      auto_resume_count = download::DownloadItemImpl::kMaxAutoResumeAttempts;
-    }
+    // For history download only as history don't have auto resumption count
+    // saved.
+    int auto_resume_count = download::DownloadItemImpl::kMaxAutoResumeAttempts;
 
     return new download::DownloadItemImpl(
         delegate, guid, download_id, current_path, target_path, url_chain,
diff --git a/content/browser/frame_host/debug_urls.cc b/content/browser/frame_host/debug_urls.cc
index fc475c8..d1f8023 100644
--- a/content/browser/frame_host/debug_urls.cc
+++ b/content/browser/frame_host/debug_urls.cc
@@ -128,23 +128,16 @@
 
 }  // namespace
 
-bool HandleDebugURL(const GURL& url, ui::PageTransition transition) {
-  // Ensure that the user explicitly navigated to this URL, unless
-  // kEnableGpuBenchmarking is enabled by Telemetry.
+bool HandleDebugURL(const GURL& url,
+                    ui::PageTransition transition,
+                    bool is_explicit_navigation) {
+  // We want to handle the debug URL if the user explicitly navigated to this
+  // URL, unless kEnableGpuBenchmarking is enabled by Telemetry.
   bool is_telemetry_navigation =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           cc::switches::kEnableGpuBenchmarking) &&
       (PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED));
 
-  // TODO(crbug.com/986346): allow this behavior to be customized by the
-  // embedder.
-  bool is_explicit_navigation =
-#if defined(ENABLE_ADDRESS_BAR)
-      transition & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR;
-#else
-      ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED);
-#endif
-
   if (!is_explicit_navigation && !is_telemetry_navigation)
     return false;
 
diff --git a/content/browser/frame_host/debug_urls.h b/content/browser/frame_host/debug_urls.h
index 189ac16..fbeb6603 100644
--- a/content/browser/frame_host/debug_urls.h
+++ b/content/browser/frame_host/debug_urls.h
@@ -14,7 +14,9 @@
 
 // Checks if the given url is a url used for debugging purposes, and if so
 // handles it and returns true.
-bool HandleDebugURL(const GURL& url, ui::PageTransition transition);
+bool HandleDebugURL(const GURL& url,
+                    ui::PageTransition transition,
+                    bool is_explicit_navigation);
 
 }  // namespace content
 
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index 3f207fcf..30e765cc 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -926,7 +926,11 @@
   TRACE_EVENT1("browser,navigation",
                "NavigationControllerImpl::LoadURLWithParams",
                "url", params.url.possibly_invalid_spec());
-  if (HandleDebugURL(params.url, params.transition_type)) {
+  bool is_explicit_navigation =
+      GetContentClient()->browser()->IsExplicitNavigation(
+          params.transition_type);
+  if (HandleDebugURL(params.url, params.transition_type,
+                     is_explicit_navigation)) {
     // If Telemetry is running, allow the URL load to proceed as if it's
     // unhandled, otherwise Telemetry can't tell if Navigation completed.
     if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/content/browser/media/audio_input_stream_broker_unittest.cc b/content/browser/media/audio_input_stream_broker_unittest.cc
index b77cc06..7bda816c 100644
--- a/content/browser/media/audio_input_stream_broker_unittest.cc
+++ b/content/browser/media/audio_input_stream_broker_unittest.cc
@@ -12,6 +12,7 @@
 #include "content/public/test/browser_task_environment.h"
 #include "media/mojo/mojom/audio_input_stream.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "services/audio/public/cpp/fake_stream_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -159,7 +160,8 @@
   StrictMock<MockRendererAudioInputStreamFactoryClient> renderer_factory_client;
   std::unique_ptr<AudioInputStreamBroker> broker;
   MockStreamFactory stream_factory;
-  audio::mojom::StreamFactoryPtr factory_ptr{stream_factory.MakeRemote()};
+  mojo::Remote<audio::mojom::StreamFactory> factory_ptr{
+      stream_factory.MakeRemote()};
 };
 
 }  // namespace
diff --git a/content/browser/media/audio_loopback_stream_broker_unittest.cc b/content/browser/media/audio_loopback_stream_broker_unittest.cc
index 608ea36..51fb645c 100644
--- a/content/browser/media/audio_loopback_stream_broker_unittest.cc
+++ b/content/browser/media/audio_loopback_stream_broker_unittest.cc
@@ -11,6 +11,8 @@
 #include "base/test/mock_callback.h"
 #include "content/public/test/browser_task_environment.h"
 #include "media/mojo/mojom/audio_input_stream.mojom.h"
+#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "services/audio/public/cpp/fake_stream_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -110,7 +112,7 @@
     base::UnguessableToken group_id;
     mojo::ScopedSharedBufferHandle key_press_count_buffer;
     CreateLoopbackStreamCallback created_callback;
-    audio::mojom::LocalMuterAssociatedRequest muter_request;
+    mojo::PendingAssociatedReceiver<audio::mojom::LocalMuter> muter_receiver;
   };
 
   void ExpectStreamCreation(StreamRequestData* ex) {
@@ -143,7 +145,7 @@
   void BindMuter(
       mojo::PendingAssociatedReceiver<audio::mojom::LocalMuter> receiver,
       const base::UnguessableToken& group_id) final {
-    stream_request_data_->muter_request = std::move(receiver);
+    stream_request_data_->muter_receiver = std::move(receiver);
     IsMuting(group_id);
   }
 
@@ -172,7 +174,8 @@
   StrictMock<MockRendererAudioInputStreamFactoryClient> renderer_factory_client;
   std::unique_ptr<AudioLoopbackStreamBroker> broker;
   MockStreamFactory stream_factory;
-  audio::mojom::StreamFactoryPtr factory_ptr{stream_factory.MakeRemote()};
+  mojo::Remote<audio::mojom::StreamFactory> factory_ptr{
+      stream_factory.MakeRemote()};
 };
 
 }  // namespace
diff --git a/content/browser/media/audio_output_stream_broker_unittest.cc b/content/browser/media/audio_output_stream_broker_unittest.cc
index c4b9717c..917651c 100644
--- a/content/browser/media/audio_output_stream_broker_unittest.cc
+++ b/content/browser/media/audio_output_stream_broker_unittest.cc
@@ -19,6 +19,7 @@
 #include "media/mojo/mojom/audio_output_stream.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/system/buffer.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "services/audio/public/cpp/fake_stream_factory.h"
@@ -158,7 +159,8 @@
   StrictMock<MockAudioOutputStreamProviderClient> provider_client;
   std::unique_ptr<AudioOutputStreamBroker> broker;
   MockStreamFactory stream_factory;
-  audio::mojom::StreamFactoryPtr factory_ptr{stream_factory.MakeRemote()};
+  mojo::Remote<audio::mojom::StreamFactory> factory_ptr{
+      stream_factory.MakeRemote()};
 };
 
 }  // namespace
diff --git a/content/browser/media/forwarding_audio_stream_factory.cc b/content/browser/media/forwarding_audio_stream_factory.cc
index 141b5e0..8dd3387 100644
--- a/content/browser/media/forwarding_audio_stream_factory.cc
+++ b/content/browser/media/forwarding_audio_stream_factory.cc
@@ -315,10 +315,10 @@
     TRACE_EVENT_INSTANT1(
         "audio", "ForwardingAudioStreamFactory: Binding new factory",
         TRACE_EVENT_SCOPE_THREAD, "group", group_id_.GetLowForSerialization());
-    connector_->BindInterface(audio::mojom::kServiceName,
-                              mojo::MakeRequest(&remote_factory_));
+    connector_->Connect(audio::mojom::kServiceName,
+                        remote_factory_.BindNewPipeAndPassReceiver());
     // Unretained is safe because |this| owns |remote_factory_|.
-    remote_factory_.set_connection_error_handler(base::BindOnce(
+    remote_factory_.set_disconnect_handler(base::BindOnce(
         &ForwardingAudioStreamFactory::Core::ResetRemoteFactoryPtr,
         base::Unretained(this)));
 
diff --git a/content/browser/media/forwarding_audio_stream_factory.h b/content/browser/media/forwarding_audio_stream_factory.h
index 295af3e..98193c2f 100644
--- a/content/browser/media/forwarding_audio_stream_factory.h
+++ b/content/browser/media/forwarding_audio_stream_factory.h
@@ -21,6 +21,7 @@
 #include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "media/mojo/mojom/audio_output_stream.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/audio/public/mojom/audio_processing.mojom.h"
 #include "services/audio/public/mojom/stream_factory.mojom.h"
 
@@ -153,7 +154,7 @@
     // since we want to clean up the service when not in use. If we have active
     // muting but nothing else, we should stop it and start it again when we
     // need to reacquire the factory for some other reason.
-    audio::mojom::StreamFactoryPtr remote_factory_;
+    mojo::Remote<audio::mojom::StreamFactory> remote_factory_;
 
     // Running id used for tracking audible streams. We keep count here to avoid
     // collisions.
diff --git a/content/browser/payments/payment_app.proto b/content/browser/payments/payment_app.proto
index 35848b1d..71f3144 100644
--- a/content/browser/payments/payment_app.proto
+++ b/content/browser/payments/payment_app.proto
@@ -41,6 +41,13 @@
   optional string id = 2;
 }
 
+message SupportedDelegationsProto {
+  optional bool shipping_address = 1;
+  optional bool payer_name = 2;
+  optional bool payer_phone = 3;
+  optional bool payer_email = 4;
+}
+
 message StoredPaymentAppProto {
   optional int64 registration_id = 1;
   optional string scope = 2;
@@ -49,4 +56,5 @@
   optional bool prefer_related_applications = 5;
   repeated StoredRelatedApplicationProto related_applications = 6;
   optional string user_hint = 7;
+  optional SupportedDelegationsProto supported_delegations = 8;
 }
diff --git a/content/browser/payments/payment_app_database.cc b/content/browser/payments/payment_app_database.cc
index 29765ac..b13f19e 100644
--- a/content/browser/payments/payment_app_database.cc
+++ b/content/browser/payments/payment_app_database.cc
@@ -26,6 +26,7 @@
 namespace content {
 namespace {
 
+using ::payments::mojom::PaymentDelegation;
 using ::payments::mojom::PaymentHandlerStatus;
 using ::payments::mojom::PaymentInstrument;
 using ::payments::mojom::PaymentInstrumentPtr;
@@ -86,6 +87,28 @@
   return instrument;
 }
 
+StoredSupportedDelegations ToStoredSupportedDelegations(
+    const content::SupportedDelegationsProto& supported_delegations_proto) {
+  StoredSupportedDelegations supported_delegations;
+  if (supported_delegations_proto.has_shipping_address()) {
+    supported_delegations.shipping_address =
+        supported_delegations_proto.shipping_address();
+  }
+  if (supported_delegations_proto.has_payer_name()) {
+    supported_delegations.payer_name = supported_delegations_proto.payer_name();
+  }
+  if (supported_delegations_proto.has_payer_email()) {
+    supported_delegations.payer_email =
+        supported_delegations_proto.payer_email();
+  }
+  if (supported_delegations_proto.has_payer_phone()) {
+    supported_delegations.payer_phone =
+        supported_delegations_proto.payer_phone();
+  }
+
+  return supported_delegations;
+}
+
 std::unique_ptr<StoredPaymentApp> ToStoredPaymentApp(const std::string& input) {
   StoredPaymentAppProto app_proto;
   if (!app_proto.ParseFromString(input))
@@ -102,6 +125,8 @@
     app->related_applications.back().id = related_app.id();
   }
   app->user_hint = app_proto.user_hint();
+  app->supported_delegations =
+      ToStoredSupportedDelegations(app_proto.supported_delegations());
 
   if (!app_proto.icon().empty()) {
     std::string icon_raw_data;
@@ -368,6 +393,99 @@
           weak_ptr_factory_.GetWeakPtr(), user_hint));
 }
 
+void PaymentAppDatabase::EnablePaymentAppDelegations(
+    const GURL& scope,
+    const std::vector<PaymentDelegation>& delegations,
+    EnableDelegationsCallback callback) {
+  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+
+  service_worker_context_->FindReadyRegistrationForScope(
+      scope,
+      base::BindOnce(
+          &PaymentAppDatabase::DidFindRegistrationToEnablePaymentAppDelegations,
+          weak_ptr_factory_.GetWeakPtr(), delegations, std::move(callback)));
+}
+
+void PaymentAppDatabase::DidFindRegistrationToEnablePaymentAppDelegations(
+    const std::vector<PaymentDelegation>& delegations,
+    EnableDelegationsCallback callback,
+    blink::ServiceWorkerStatusCode status,
+    scoped_refptr<ServiceWorkerRegistration> registration) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (status != blink::ServiceWorkerStatusCode::kOk) {
+    std::move(callback).Run(PaymentHandlerStatus::NO_ACTIVE_WORKER);
+    return;
+  }
+
+  service_worker_context_->GetRegistrationUserDataByKeyPrefix(
+      registration->id(), CreatePaymentAppKey(registration->scope().spec()),
+      base::BindOnce(
+          &PaymentAppDatabase::DidGetPaymentAppInfoToEnableDelegations,
+          weak_ptr_factory_.GetWeakPtr(), delegations, std::move(callback),
+          registration->id(), registration->scope()));
+}
+
+void PaymentAppDatabase::DidGetPaymentAppInfoToEnableDelegations(
+    const std::vector<PaymentDelegation>& delegations,
+    EnableDelegationsCallback callback,
+    int64_t registration_id,
+    const GURL& pattern,
+    const std::vector<std::string>& data,
+    blink::ServiceWorkerStatusCode status) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (status != blink::ServiceWorkerStatusCode::kOk) {
+    std::move(callback).Run(PaymentHandlerStatus::NOT_FOUND);
+    return;
+  }
+
+  DCHECK_LE(data.size(), 1U);
+  StoredPaymentAppProto app_proto;
+  if (data.size() == 1U) {
+    app_proto.ParseFromString(data[0]);
+  }
+
+  auto supported_delegations_proto =
+      std::make_unique<SupportedDelegationsProto>();
+  for (auto delegation : delegations) {
+    switch (delegation) {
+      case PaymentDelegation::SHIPPING_ADDRESS:
+        supported_delegations_proto->set_shipping_address(true);
+        break;
+      case PaymentDelegation::PAYER_NAME:
+        supported_delegations_proto->set_payer_name(true);
+        break;
+      case PaymentDelegation::PAYER_PHONE:
+        supported_delegations_proto->set_payer_phone(true);
+        break;
+      case PaymentDelegation::PAYER_EMAIL:
+        supported_delegations_proto->set_payer_email(true);
+        break;
+    }
+  }
+  app_proto.set_allocated_supported_delegations(
+      supported_delegations_proto.release());
+
+  std::string serialized_payment_app;
+  bool success = app_proto.SerializeToString(&serialized_payment_app);
+  DCHECK(success);
+
+  service_worker_context_->StoreRegistrationUserData(
+      registration_id, pattern.GetOrigin(),
+      {{CreatePaymentAppKey(pattern.spec()), serialized_payment_app}},
+      base::BindOnce(&PaymentAppDatabase::DidEnablePaymentAppDelegations,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void PaymentAppDatabase::DidEnablePaymentAppDelegations(
+    EnableDelegationsCallback callback,
+    blink::ServiceWorkerStatusCode status) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  return std::move(callback).Run(
+      status == blink::ServiceWorkerStatusCode::kOk
+          ? PaymentHandlerStatus::SUCCESS
+          : PaymentHandlerStatus::STORAGE_OPERATION_FAILED);
+}
+
 void PaymentAppDatabase::DidFindRegistrationToSetPaymentAppUserHint(
     const std::string& user_hint,
     blink::ServiceWorkerStatusCode status,
diff --git a/content/browser/payments/payment_app_database.h b/content/browser/payments/payment_app_database.h
index 9c1cbb4..9e4a527 100644
--- a/content/browser/payments/payment_app_database.h
+++ b/content/browser/payments/payment_app_database.h
@@ -48,6 +48,8 @@
       base::OnceCallback<void(payments::mojom::PaymentHandlerStatus)>;
   using SetPaymentAppInfoCallback =
       base::OnceCallback<void(payments::mojom::PaymentHandlerStatus)>;
+  using EnableDelegationsCallback =
+      base::OnceCallback<void(payments::mojom::PaymentHandlerStatus)>;
 
   explicit PaymentAppDatabase(
       scoped_refptr<ServiceWorkerContextWrapper> service_worker_context);
@@ -77,6 +79,10 @@
   void ClearPaymentInstruments(const GURL& scope,
                                ClearPaymentInstrumentsCallback callback);
   void SetPaymentAppUserHint(const GURL& scope, const std::string& user_hint);
+  void EnablePaymentAppDelegations(
+      const GURL& scope,
+      const std::vector<payments::mojom::PaymentDelegation>& delegations,
+      EnableDelegationsCallback callback);
   void SetPaymentAppInfoForRegisteredServiceWorker(
       int64_t registration_id,
       const std::string& instrument_key,
@@ -205,6 +211,22 @@
                                          blink::ServiceWorkerStatusCode status);
   void DidSetPaymentAppUserHint(blink::ServiceWorkerStatusCode status);
 
+  // EnablePaymentAppDelegations callbacks.
+  void DidFindRegistrationToEnablePaymentAppDelegations(
+      const std::vector<payments::mojom::PaymentDelegation>& delegations,
+      EnableDelegationsCallback callback,
+      blink::ServiceWorkerStatusCode status,
+      scoped_refptr<ServiceWorkerRegistration> registration);
+  void DidGetPaymentAppInfoToEnableDelegations(
+      const std::vector<payments::mojom::PaymentDelegation>& delegations,
+      EnableDelegationsCallback callback,
+      int64_t registration_id,
+      const GURL& pattern,
+      const std::vector<std::string>& data,
+      blink::ServiceWorkerStatusCode status);
+  void DidEnablePaymentAppDelegations(EnableDelegationsCallback callback,
+                                      blink::ServiceWorkerStatusCode status);
+
   // SetPaymentAppInfoForRegisteredServiceWorker callbacks.
   void DidFindRegistrationToSetPaymentApp(
       const std::string& instrument_key,
diff --git a/content/browser/payments/payment_manager.cc b/content/browser/payments/payment_manager.cc
index 6ad629fd..cc640d8 100644
--- a/content/browser/payments/payment_manager.cc
+++ b/content/browser/payments/payment_manager.cc
@@ -138,6 +138,15 @@
       scope_, user_hint);
 }
 
+void PaymentManager::EnableDelegations(
+    const std::vector<payments::mojom::PaymentDelegation>& delegations,
+    PaymentManager::EnableDelegationsCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  payment_app_context_->payment_app_database()->EnablePaymentAppDelegations(
+      scope_, delegations, std::move(callback));
+}
+
 void PaymentManager::OnConnectionError() {
   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
   payment_app_context_->PaymentManagerHadConnectionError(this);
diff --git a/content/browser/payments/payment_manager.h b/content/browser/payments/payment_manager.h
index b35ec0d2..3d0029f 100644
--- a/content/browser/payments/payment_manager.h
+++ b/content/browser/payments/payment_manager.h
@@ -48,6 +48,9 @@
   void ClearPaymentInstruments(
       ClearPaymentInstrumentsCallback callback) override;
   void SetUserHint(const std::string& user_hint) override;
+  void EnableDelegations(
+      const std::vector<payments::mojom::PaymentDelegation>& delegations,
+      EnableDelegationsCallback callback) override;
 
   // Called when an error is detected on binding_.
   void OnConnectionError();
diff --git a/content/browser/renderer_host/frame_sink_provider_impl.cc b/content/browser/renderer_host/frame_sink_provider_impl.cc
index 95b7e61..47ea521 100644
--- a/content/browser/renderer_host/frame_sink_provider_impl.cc
+++ b/content/browser/renderer_host/frame_sink_provider_impl.cc
@@ -45,7 +45,8 @@
     int32_t widget_id,
     mojom::RenderFrameMetadataObserverClientRequest
         render_frame_metadata_observer_client_request,
-    mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer) {
+    mojo::PendingRemote<mojom::RenderFrameMetadataObserver>
+        render_frame_metadata_observer) {
   RenderWidgetHostImpl* render_widget_host_impl =
       RenderWidgetHostImpl::FromID(process_id_, widget_id);
   if (!render_widget_host_impl) {
diff --git a/content/browser/renderer_host/frame_sink_provider_impl.h b/content/browser/renderer_host/frame_sink_provider_impl.h
index 6c3ddca5..c90fb47 100644
--- a/content/browser/renderer_host/frame_sink_provider_impl.h
+++ b/content/browser/renderer_host/frame_sink_provider_impl.h
@@ -8,6 +8,7 @@
 #include "content/common/frame_sink_provider.mojom.h"
 #include "content/common/render_frame_metadata.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 
 namespace content {
@@ -32,7 +33,8 @@
       int32_t widget_id,
       mojom::RenderFrameMetadataObserverClientRequest
           render_frame_metadata_observer_client_request,
-      mojom::RenderFrameMetadataObserverPtr observer) override;
+      mojo::PendingRemote<mojom::RenderFrameMetadataObserver> observer)
+      override;
 
  private:
   const int32_t process_id_;
diff --git a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
index a76e48d..6d0d121 100644
--- a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
+++ b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
@@ -33,8 +33,10 @@
 #include "media/audio/test_audio_thread.h"
 #include "media/base/audio_parameters.h"
 #include "media/mojo/mojom/audio_data_pipe.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/interface_request.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 "services/audio/public/cpp/fake_stream_factory.h"
 #include "services/audio/public/mojom/constants.mojom.h"
 #include "services/audio/public/mojom/stream_factory.mojom.h"
@@ -94,15 +96,16 @@
     RenderViewHostTestHarness::TearDown();
   }
 
-  void BindFactory(mojo::ScopedMessagePipeHandle factory_request) {
-    audio_service_stream_factory_.binding_.Bind(
-        audio::mojom::StreamFactoryRequest(std::move(factory_request)));
+  void BindFactory(mojo::ScopedMessagePipeHandle factory_receiver) {
+    audio_service_stream_factory_.receiver_.Bind(
+        mojo::PendingReceiver<audio::mojom::StreamFactory>(
+            std::move(factory_receiver)));
   }
 
   class MockStreamFactory : public audio::FakeStreamFactory {
    public:
-    MockStreamFactory() : binding_(this) {}
-    ~MockStreamFactory() override {}
+    MockStreamFactory() = default;
+    ~MockStreamFactory() override = default;
 
     void CreateInputStream(
         mojo::PendingReceiver<media::mojom::AudioInputStream> stream_receiver,
@@ -133,7 +136,7 @@
     CreateInputStreamCallback last_created_callback;
     CreateLoopbackStreamCallback last_created_loopback_callback;
 
-    mojo::Binding<audio::mojom::StreamFactory> binding_;
+    mojo::Receiver<audio::mojom::StreamFactory> receiver_{this};
   };
 
   class FakeRendererAudioInputStreamFactoryClient
diff --git a/content/browser/renderer_host/render_frame_metadata_provider_impl.cc b/content/browser/renderer_host/render_frame_metadata_provider_impl.cc
index 0b18a02..527a9e64 100644
--- a/content/browser/renderer_host/render_frame_metadata_provider_impl.cc
+++ b/content/browser/renderer_host/render_frame_metadata_provider_impl.cc
@@ -28,8 +28,9 @@
 
 void RenderFrameMetadataProviderImpl::Bind(
     mojom::RenderFrameMetadataObserverClientRequest client_request,
-    mojom::RenderFrameMetadataObserverPtr observer) {
-  render_frame_metadata_observer_ptr_ = std::move(observer);
+    mojo::PendingRemote<mojom::RenderFrameMetadataObserver> observer) {
+  render_frame_metadata_observer_remote_.reset();
+  render_frame_metadata_observer_remote_.Bind(std::move(observer));
   render_frame_metadata_observer_client_binding_.Close();
   render_frame_metadata_observer_client_binding_.Bind(std::move(client_request),
                                                       task_runner_);
@@ -51,24 +52,24 @@
 #if defined(OS_ANDROID)
 void RenderFrameMetadataProviderImpl::ReportAllRootScrollsForAccessibility(
     bool enabled) {
-  if (!render_frame_metadata_observer_ptr_) {
+  if (!render_frame_metadata_observer_remote_) {
     pending_report_all_root_scrolls_for_accessibility_ = enabled;
     return;
   }
 
-  render_frame_metadata_observer_ptr_->ReportAllRootScrollsForAccessibility(
+  render_frame_metadata_observer_remote_->ReportAllRootScrollsForAccessibility(
       enabled);
 }
 #endif
 
 void RenderFrameMetadataProviderImpl::ReportAllFrameSubmissionsForTesting(
     bool enabled) {
-  if (!render_frame_metadata_observer_ptr_) {
+  if (!render_frame_metadata_observer_remote_) {
     pending_report_all_frame_submission_for_testing_ = enabled;
     return;
   }
 
-  render_frame_metadata_observer_ptr_->ReportAllFrameSubmissionsForTesting(
+  render_frame_metadata_observer_remote_->ReportAllFrameSubmissionsForTesting(
       enabled);
 }
 
diff --git a/content/browser/renderer_host/render_frame_metadata_provider_impl.h b/content/browser/renderer_host/render_frame_metadata_provider_impl.h
index f7d0ca9..10455e9 100644
--- a/content/browser/renderer_host/render_frame_metadata_provider_impl.h
+++ b/content/browser/renderer_host/render_frame_metadata_provider_impl.h
@@ -12,6 +12,8 @@
 #include "content/common/render_frame_metadata.mojom.h"
 #include "content/public/browser/render_frame_metadata_provider.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace content {
 class FrameTokenMessageQueue;
@@ -37,7 +39,7 @@
   void RemoveObserver(Observer* observer) override;
 
   void Bind(mojom::RenderFrameMetadataObserverClientRequest client_request,
-            mojom::RenderFrameMetadataObserverPtr observer);
+            mojo::PendingRemote<mojom::RenderFrameMetadataObserver> observer);
 
   const cc::RenderFrameMetadata& LastRenderFrameMetadata() override;
 
@@ -86,7 +88,8 @@
 
   mojo::Binding<mojom::RenderFrameMetadataObserverClient>
       render_frame_metadata_observer_client_binding_;
-  mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer_ptr_;
+  mojo::Remote<mojom::RenderFrameMetadataObserver>
+      render_frame_metadata_observer_remote_;
 
 #if defined(OS_ANDROID)
   base::Optional<bool> pending_report_all_root_scrolls_for_accessibility_;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index a0634fd3..b6f89d4 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1801,6 +1801,7 @@
   // surprising behavior.
   remote_route_provider_.reset();
   channel_->GetRemoteAssociatedInterface(&remote_route_provider_);
+  renderer_interface_.reset();
   channel_->GetRemoteAssociatedInterface(&renderer_interface_);
 
   // We start the Channel in a paused state. It will be briefly unpaused again
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index e6c9ca93..790327e 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -920,7 +920,7 @@
 
   mojo::Remote<mojom::ChildProcess> child_process_;
   mojo::AssociatedRemote<mojom::RouteProvider> remote_route_provider_;
-  mojom::RendererAssociatedPtr renderer_interface_;
+  mojo::AssociatedRemote<mojom::Renderer> renderer_interface_;
   mojo::AssociatedBinding<mojom::RendererHost> renderer_host_binding_;
 
   // Tracks active audio and video streams within the render process; used to
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index ccd24b0..290200a 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2962,7 +2962,8 @@
 void RenderWidgetHostImpl::RegisterRenderFrameMetadataObserver(
     mojom::RenderFrameMetadataObserverClientRequest
         render_frame_metadata_observer_client_request,
-    mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer) {
+    mojo::PendingRemote<mojom::RenderFrameMetadataObserver>
+        render_frame_metadata_observer) {
   render_frame_metadata_provider_.Bind(
       std::move(render_frame_metadata_observer_client_request),
       std::move(render_frame_metadata_observer));
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 3620b461..49eaed1 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -58,6 +58,7 @@
 #include "ipc/ipc_listener.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h"
 #include "services/viz/public/mojom/hit_test/input_target_client.mojom.h"
@@ -652,7 +653,8 @@
   void RegisterRenderFrameMetadataObserver(
       mojom::RenderFrameMetadataObserverClientRequest
           render_frame_metadata_observer_client_request,
-      mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer);
+      mojo::PendingRemote<mojom::RenderFrameMetadataObserver>
+          render_frame_metadata_observer);
 
   RenderFrameMetadataProviderImpl* render_frame_metadata_provider() {
     return &render_frame_metadata_provider_;
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index c98beec..d9638ea 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -53,6 +53,8 @@
 #include "content/test/stub_render_widget_host_owner_delegate.h"
 #include "content/test/test_render_view_host.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/display/screen.h"
@@ -270,7 +272,7 @@
     : public mojom::RenderFrameMetadataObserver {
  public:
   FakeRenderFrameMetadataObserver(
-      mojom::RenderFrameMetadataObserverRequest request,
+      mojo::PendingReceiver<mojom::RenderFrameMetadataObserver> receiver,
       mojom::RenderFrameMetadataObserverClientPtrInfo client_info);
   ~FakeRenderFrameMetadataObserver() override {}
 
@@ -280,15 +282,15 @@
   void ReportAllFrameSubmissionsForTesting(bool enabled) override {}
 
  private:
-  mojom::RenderFrameMetadataObserverRequest request_;
+  mojo::PendingReceiver<mojom::RenderFrameMetadataObserver> receiver_;
   mojom::RenderFrameMetadataObserverClientPtrInfo client_info_;
   DISALLOW_COPY_AND_ASSIGN(FakeRenderFrameMetadataObserver);
 };
 
 FakeRenderFrameMetadataObserver::FakeRenderFrameMetadataObserver(
-    mojom::RenderFrameMetadataObserverRequest request,
+    mojo::PendingReceiver<mojom::RenderFrameMetadataObserver> receiver,
     mojom::RenderFrameMetadataObserverClientPtrInfo client_info)
-    : request_(std::move(request)), client_info_(std::move(client_info)) {}
+    : receiver_(std::move(receiver)), client_info_(std::move(client_info)) {}
 
 // MockRenderWidgetHostDelegate --------------------------------------------
 
@@ -505,11 +507,8 @@
         std::make_unique<FakeRendererCompositorFrameSink>(
             std::move(sink), std::move(client_request));
 
-    mojom::RenderFrameMetadataObserverPtr
-        renderer_render_frame_metadata_observer_ptr;
-    mojom::RenderFrameMetadataObserverRequest
-        render_frame_metadata_observer_request =
-            mojo::MakeRequest(&renderer_render_frame_metadata_observer_ptr);
+    mojo::PendingRemote<mojom::RenderFrameMetadataObserver>
+        renderer_render_frame_metadata_observer_remote;
     mojom::RenderFrameMetadataObserverClientPtrInfo
         render_frame_metadata_observer_client_info;
     mojom::RenderFrameMetadataObserverClientRequest
@@ -517,7 +516,8 @@
             mojo::MakeRequest(&render_frame_metadata_observer_client_info);
     renderer_render_frame_metadata_observer_ =
         std::make_unique<FakeRenderFrameMetadataObserver>(
-            std::move(render_frame_metadata_observer_request),
+            renderer_render_frame_metadata_observer_remote
+                .InitWithNewPipeAndPassReceiver(),
             std::move(render_frame_metadata_observer_client_info));
 
     host_->RequestCompositorFrameSink(
@@ -525,7 +525,7 @@
         std::move(renderer_compositor_frame_sink_ptr_));
     host_->RegisterRenderFrameMetadataObserver(
         std::move(render_frame_metadata_observer_client_request),
-        std::move(renderer_render_frame_metadata_observer_ptr));
+        std::move(renderer_render_frame_metadata_observer_remote));
   }
 
   void TearDown() override {
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index 2ae90677..16a8769 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -23,7 +23,7 @@
 #include "content/common/content_export.h"
 #include "content/common/render_widget_host_ns_view.mojom.h"
 #include "ipc/ipc_sender.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/accelerated_widget_mac/accelerated_widget_mac.h"
 #include "ui/base/cocoa/accessibility_focus_overrider.h"
@@ -537,11 +537,11 @@
 
   // If the NSView is hosted in a remote process and accessed via mojo then
   // - |ns_view_| will point to |remote_ns_view_|
-  // - |remote_ns_view_client_binding_| is the binding provided to the bridge.
+  // - |remote_ns_view_client_receiver_| is the receiver provided to the bridge.
   mojo::AssociatedRemote<remote_cocoa::mojom::RenderWidgetHostNSView>
       remote_ns_view_;
-  mojo::AssociatedBinding<remote_cocoa::mojom::RenderWidgetHostNSViewHost>
-      remote_ns_view_client_binding_;
+  mojo::AssociatedReceiver<remote_cocoa::mojom::RenderWidgetHostNSViewHost>
+      remote_ns_view_client_receiver_{this};
 
   // State tracked by Show/Hide/IsShowing.
   bool is_visible_ = false;
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index df19099..ed9ea518 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -174,7 +174,6 @@
     : RenderWidgetHostViewBase(widget),
       page_at_minimum_scale_(true),
       mouse_wheel_phase_handler_(this),
-      remote_ns_view_client_binding_(this),
       is_loading_(false),
       is_guest_view_hack_(is_guest_view_hack),
       popup_parent_host_view_(nullptr),
@@ -248,9 +247,9 @@
   remote_window_accessible_.reset();
 
   // Disconnect from the previous bridge (this will have the effect of
-  // destroying the associated bridge), and close the binding (to allow it
+  // destroying the associated bridge), and close the receiver (to allow it
   // to be re-bound). Note that |in_process_ns_view_bridge_| remains valid.
-  remote_ns_view_client_binding_.Close();
+  remote_ns_view_client_receiver_.reset();
   remote_ns_view_.reset();
 
   // Enable accessibility focus overriding for remote NSViews.
@@ -263,8 +262,8 @@
     return;
   }
 
-  remote_cocoa::mojom::RenderWidgetHostNSViewHostAssociatedPtr client;
-  remote_ns_view_client_binding_.Bind(mojo::MakeRequest(&client));
+  mojo::PendingAssociatedRemote<remote_cocoa::mojom::RenderWidgetHostNSViewHost>
+      client = remote_ns_view_client_receiver_.BindNewEndpointAndPassRemote();
   mojo::PendingAssociatedReceiver<remote_cocoa::mojom::RenderWidgetHostNSView>
       view_receiver = remote_ns_view_.BindNewEndpointAndPassReceiver();
 
@@ -274,7 +273,7 @@
   // TODO(ccameron): Remove the need for this cast.
   // https://crbug.com/888290
   mojo::AssociatedInterfacePtrInfo<remote_cocoa::mojom::StubInterface>
-      stub_client(client.PassInterface().PassHandle(), 0);
+      stub_client(client.PassHandle(), 0);
   remote_cocoa::mojom::StubInterfaceAssociatedRequest stub_bridge_request(
       view_receiver.PassHandle());
 
@@ -701,7 +700,7 @@
   // the other side of |ns_view_| may outlive us due to other retains.
   ns_view_ = nullptr;
   in_process_ns_view_bridge_.reset();
-  remote_ns_view_client_binding_.Close();
+  remote_ns_view_client_receiver_.reset();
   remote_ns_view_.reset();
 
   // Delete the delegated frame state, which will reach back into
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc
index 620e9c6..653535a7 100644
--- a/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -337,6 +337,14 @@
 }
 
 TEST_F(EmbeddedWorkerInstanceTest, DetachDuringProcessAllocation) {
+  if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) {
+    // This test calls Start() then Detach() to test detaching during process
+    // allocation. But when ServiceWorkerOnUI is enabled, Start() synchronously
+    // reaches the SetupOnUIThread() step, so process allocation occurs before
+    // Detach() is called, so this test doesn't make sense.
+    return;
+  }
+
   const GURL scope("http://example.com/");
   const GURL url("http://example.com/worker.js");
 
@@ -394,6 +402,14 @@
 }
 
 TEST_F(EmbeddedWorkerInstanceTest, StopDuringProcessAllocation) {
+  if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) {
+    // This test calls Start() then Stop() to test stopping during process
+    // allocation. But when ServiceWorkerOnUI is enabled, Start() synchronously
+    // reaches the SetupOnUIThread() step, so process allocation occurs before
+    // Stop() is called, so this test doesn't make sense.
+    return;
+  }
+
   const GURL scope("http://example.com/");
   const GURL url("http://example.com/worker.js");
 
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 57cc541d..58d77940 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -3368,9 +3368,8 @@
 
     ASSERT_EQ(CacheStorageError::kSuccess, error);
     ASSERT_TRUE(response->blob);
-    blink::mojom::BlobPtr blob_ptr(std::move(response->blob->blob));
-    auto blob_handle =
-        base::MakeRefCounted<storage::BlobHandle>(std::move(blob_ptr));
+    auto blob_handle = base::MakeRefCounted<storage::BlobHandle>(
+        std::move(response->blob->blob));
     blob_handle->get()->ReadSideData(base::BindOnce(
         [](scoped_refptr<storage::BlobHandle> blob_handle, int* result,
            base::OnceClosure continuation,
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 5550c69..3cb0de9 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -2781,8 +2781,9 @@
   DownloadImageTestInternal(shell(), kImageUrl, 0, 0);
 }
 
+// Disabled due to flakiness: https://crbug.com/1002755.
 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
-                       DownloadImage_Allow_FileImage) {
+                       DISABLED_DownloadImage_Allow_FileImage) {
   shell()->LoadURL(GetTestUrl("", "simple_page.html"));
 
   const GURL kImageUrl =
diff --git a/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc b/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc
index 1cabed29..eb81cd3b 100644
--- a/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc
+++ b/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc
@@ -24,7 +24,7 @@
 
 // See content/test/data/sxg/README on how to generate these data.
 // clang-format off
-constexpr char kSignatureHeaderECDSAP256[] = R"(label;cert-sha256=*FliHUDteraIzN1Q2AZLxPtQrQdJUiFCe/gwwSNxdfVU=*;cert-url="https://example.com/cert.msg";date=1517892341;expires=1517895941;integrity="digest/mi-sha256-03";sig=*MEUCIBcqXwHFKHJx/zC6tPvraxfCfjnZymD8ezx1gOCMMB7tAiEApmDS7Kr13YHhau8NGxffYBMFBUwM3qblxDj5ne9tCDg=*;validity-url="https://test.example.org/resource.validity.msg")";
+constexpr char kSignatureHeaderECDSAP256[] = R"(label;cert-sha256=*4gNFIZRsc0QyiaUY/ekUZU6h3q/1mtQafd53/yaF5Ms=*;cert-url="https://example.com/cert.msg";date=1517892341;expires=1517895941;integrity="digest/mi-sha256-03";sig=*MEYCIQDLap5Ns9tI0JmCr1nc58GTHqzyfWJmTiZ+AIPt0OBE6gIhAJ8uHk3RyxX0/pnMmmKKdr63T0XHqyz00aaxuECJ4Ez/*;validity-url="https://test.example.org/resource.validity.msg")";
 constexpr uint8_t kCborHeadersECDSAP256[] = {
   0xa4, 0x46, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x58, 0x39, 0x6d, 0x69,
   0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2d, 0x30, 0x33, 0x3d, 0x77,
@@ -40,7 +40,7 @@
   0x69, 0x6e, 0x67, 0x4c, 0x6d, 0x69, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35,
   0x36, 0x2d, 0x30, 0x33
 };
-constexpr char kSignatureHeaderECDSAP384[] = R"(label;cert-sha256=*GqecTbre59ZUPEUJrS+k5PR7sfvpQtXAVrBsU7tl9gk=*;cert-url="https://example.com/cert.msg";date=1517892341;expires=1517895941;integrity="digest/mi-sha256-03";sig=*MGUCMQC/lMDu8L9Vb46S3wl5CFy8S82BefM+1SDZ4ZGGc8Kbc4dYPQcfXpT/xbzBQe1kpiYCMAMk/64O++b+9D7ceeokaGLkabmk9l9fWretOeW9cOMaLGEylxt95HSIlOdNSDfdjg==*;validity-url="https://test.example.org/resource.validity.msg")";
+constexpr char kSignatureHeaderECDSAP384[] = R"(label;cert-sha256=*KrfLZg1xcHbdKYZ1nb8cnUjp/6iaEo6LeQrRSV6StKw=*;cert-url="https://example.com/cert.msg";date=1517892341;expires=1517895941;integrity="digest/mi-sha256-03";sig=*MGUCMBTSH0TpKGv5JSspWU+7hYeSDwaoRzYDzxxQaDQ2kV/IQS+3bQd4SFm0dPvsPzJH7AIxAPT1MXZoEiDhu45Ssr+ubU8n68QZZ92eI7TvtsEF1LEAXtx2YYC2UARu6ok9UxtrZQ==*;validity-url="https://test.example.org/resource.validity.msg")";
 // clang-format on
 
 // |expires| (1518497142) is more than 7 days (604800 seconds) after |date|
diff --git a/content/browser/web_package/signed_exchange_test_utils.h b/content/browser/web_package/signed_exchange_test_utils.h
index e9c3123..b25fdfe 100644
--- a/content/browser/web_package/signed_exchange_test_utils.h
+++ b/content/browser/web_package/signed_exchange_test_utils.h
@@ -8,9 +8,9 @@
 namespace content {
 
 constexpr char kPEMECDSAP256SPKIHash[] =
-    "gyt+9XZNn/phgPx5H8+75u0Kcr1UxLnfz1+5ccndF3A=";
+    "Roij6gF5orGtG9K8u8PkTe1LiRbVklxLM+EVABTK8I0=";
 constexpr char kPEMECDSAP384SPKIHash[] =
-    "ymo7jA8HxN67FG5u4dp9kxzM6LGvqEWLv8kCkKRguA4=";
+    "wfk/4dogHdX/MbLIvpjbKQ7fhO+ovkX2wjzDPSrIsMY=";
 
 }  // namespace content
 
diff --git a/content/common/frame_sink_provider.mojom b/content/common/frame_sink_provider.mojom
index f02c482..f82a4f91 100644
--- a/content/common/frame_sink_provider.mojom
+++ b/content/common/frame_sink_provider.mojom
@@ -21,5 +21,6 @@
       int32  widget_id,
       RenderFrameMetadataObserverClient&
         render_frame_metadata_observer_client_request,
-      RenderFrameMetadataObserver render_frame_metadata_observer);
+      pending_remote<RenderFrameMetadataObserver>
+        render_frame_metadata_observer);
 };
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h
index 2eaf3fa..d4aa3a2 100644
--- a/content/public/browser/browser_context.h
+++ b/content/public/browser/browser_context.h
@@ -19,6 +19,7 @@
 #include "base/optional.h"
 #include "base/supports_user_data.h"
 #include "content/common/content_export.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "net/url_request/url_request_interceptor.h"
 #include "net/url_request/url_request_job_factory.h"
 #include "services/network/public/mojom/cors_origin_pattern.mojom-forward.h"
@@ -169,13 +170,16 @@
   static BlobContextGetter GetBlobStorageContext(
       BrowserContext* browser_context);
 
-  // Returns a mojom::BlobPtr for a specific blob. If no blob exists with the
-  // given UUID, the BlobPtr pipe will close.
-  // This method should be called on the UI thread.
+  // Returns a mojom::mojo::PendingRemote<blink::mojom::Blob> for a specific
+  // blob. If no blob exists with the given UUID, the
+  // mojo::PendingRemote<blink::mojom::Blob> pipe will close. This method should
+  // be called on the UI thread.
   // TODO(mek): Blob UUIDs should be entirely internal to the blob system, so
-  // eliminate this method in favor of just passing around the BlobPtr directly.
-  static blink::mojom::BlobPtr GetBlobPtr(BrowserContext* browser_context,
-                                          const std::string& uuid);
+  // eliminate this method in favor of just passing around the
+  // mojo::PendingRemote<blink::mojom::Blob> directly.
+  static mojo::PendingRemote<blink::mojom::Blob> GetBlobRemote(
+      BrowserContext* browser_context,
+      const std::string& uuid);
 
   // Delivers a push message with |data| to the Service Worker identified by
   // |origin| and |service_worker_registration_id|.
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 3e5ebb5c..643a36f 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -91,6 +91,10 @@
   return true;
 }
 
+bool ContentBrowserClient::IsExplicitNavigation(ui::PageTransition transition) {
+  return transition & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR;
+}
+
 bool ContentBrowserClient::ShouldUseMobileFlingCurve() {
   return false;
 }
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index dcb77c78..44887837 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -273,6 +273,13 @@
       const GURL& candidate_url,
       const GURL& destination_url);
 
+  // Returns true if the user intentionally initiated the navigation. This is
+  // used to determine whether we should process debug URLs like chrome://crash.
+  // The default implementation checks whether the transition was initiated via
+  // the address bar (rather than whether it was typed) to permit the pasting of
+  // debug URLs.
+  virtual bool IsExplicitNavigation(ui::PageTransition transition);
+
   // Returns whether gesture fling events should use the mobile-behavior gesture
   // curve for scrolling.
   virtual bool ShouldUseMobileFlingCurve();
diff --git a/content/public/browser/stored_payment_app.cc b/content/public/browser/stored_payment_app.cc
index 7d1a747..cc7c58d7 100644
--- a/content/public/browser/stored_payment_app.cc
+++ b/content/public/browser/stored_payment_app.cc
@@ -16,6 +16,10 @@
 
 StoredCapabilities::~StoredCapabilities() = default;
 
+StoredSupportedDelegations::StoredSupportedDelegations() = default;
+
+StoredSupportedDelegations::~StoredSupportedDelegations() = default;
+
 StoredPaymentApp::StoredPaymentApp() = default;
 
 StoredPaymentApp::~StoredPaymentApp() = default;
diff --git a/content/public/browser/stored_payment_app.h b/content/public/browser/stored_payment_app.h
index 55ccba8..32024f00 100644
--- a/content/public/browser/stored_payment_app.h
+++ b/content/public/browser/stored_payment_app.h
@@ -37,6 +37,17 @@
   std::vector<int32_t> supported_card_types;
 };
 
+// This class represents the supported delegations of the StoredPaymentApp.
+struct CONTENT_EXPORT StoredSupportedDelegations {
+  StoredSupportedDelegations();
+  ~StoredSupportedDelegations();
+
+  bool shipping_address = false;
+  bool payer_name = false;
+  bool payer_phone = false;
+  bool payer_email = false;
+};
+
 // This class represents the stored payment app.
 struct CONTENT_EXPORT StoredPaymentApp {
   StoredPaymentApp();
@@ -76,6 +87,9 @@
 
   // User hint for this payment app.
   std::string user_hint;
+
+  // List of supported delegations for this payment app.
+  StoredSupportedDelegations supported_delegations;
 };
 
 }  // namespace content
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index c6f6b8ca..73efb92 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -679,20 +679,10 @@
 const base::Feature kWebRtcEcdsaDefault{"WebRTC-EnableWebRtcEcdsa",
                                         base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Enables negotiation of experimental multiplex codec in SDP.
-const base::Feature kWebRtcMultiplexCodec{"WebRTC-MultiplexCodec",
-                                          base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Use GpuMemoryBuffer backed VideoFrames in media streams.
 const base::Feature kWebRtcUseGpuMemoryBufferVideoFrames{
     "WebRTC-UseGpuMemoryBufferVideoFrames", base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Causes WebRTC to replace host ICE candidate IP addresses with generated
-// names ending in ".local" and resolve them using mDNS.
-// http://crbug.com/878465
-const base::Feature kWebRtcHideLocalIpsWithMdns{
-    "WebRtcHideLocalIpsWithMdns", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Controls whether the WebUSB API is enabled:
 // https://wicg.github.io/webusb
 const base::Feature kWebUsb{"WebUSB", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 0ca4208..e75b609 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -142,9 +142,7 @@
 CONTENT_EXPORT extern const base::Feature kWebGLImageChromium;
 CONTENT_EXPORT extern const base::Feature kWebPayments;
 CONTENT_EXPORT extern const base::Feature kWebRtcEcdsaDefault;
-CONTENT_EXPORT extern const base::Feature kWebRtcMultiplexCodec;
 CONTENT_EXPORT extern const base::Feature kWebRtcUseGpuMemoryBufferVideoFrames;
-CONTENT_EXPORT extern const base::Feature kWebRtcHideLocalIpsWithMdns;
 CONTENT_EXPORT extern const base::Feature kWebUsb;
 CONTENT_EXPORT extern const base::Feature kWebXr;
 CONTENT_EXPORT extern const base::Feature kWebXrArModule;
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index 0cb0597..10c9613 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -39,7 +39,6 @@
 #include "content/public/common/service_names.mojom.h"
 #include "content/test/not_implemented_network_url_loader_factory.h"
 #include "media/media_buildflags.h"
-#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 
 namespace content {
@@ -408,8 +407,10 @@
 
 mojom::Renderer* MockRenderProcessHost::GetRendererInterface() {
   if (!renderer_interface_) {
-    renderer_interface_.reset(new mojom::RendererAssociatedPtr);
-    mojo::MakeRequestAssociatedWithDedicatedPipe(renderer_interface_.get());
+    renderer_interface_ =
+        std::make_unique<mojo::AssociatedRemote<mojom::Renderer>>();
+    ignore_result(renderer_interface_
+                      ->BindNewEndpointAndPassDedicatedReceiverForTesting());
   }
   return renderer_interface_->get();
 }
@@ -514,7 +515,7 @@
 }
 
 void MockRenderProcessHost::OverrideRendererInterfaceForTesting(
-    std::unique_ptr<mojo::AssociatedInterfacePtr<mojom::Renderer>>
+    std::unique_ptr<mojo::AssociatedRemote<mojom::Renderer>>
         renderer_interface) {
   renderer_interface_ = std::move(renderer_interface);
 }
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index 49bc2782..0f1c488c 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -25,7 +25,7 @@
 #include "content/public/browser/render_process_host_factory.h"
 #include "ipc/ipc_test_sink.h"
 #include "media/media_buildflags.h"
-#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "net/base/network_isolation_key.h"
 #include "services/service_manager/public/cpp/identity.h"
@@ -209,7 +209,7 @@
                                 const InterfaceBinder& binder);
 
   void OverrideRendererInterfaceForTesting(
-      std::unique_ptr<mojo::AssociatedInterfacePtr<mojom::Renderer>>
+      std::unique_ptr<mojo::AssociatedRemote<mojom::Renderer>>
           renderer_interface);
 
   // SetNetworkFactory() wins over this.
@@ -246,8 +246,7 @@
   base::Process process;
   int keep_alive_ref_count_;
   int foreground_service_worker_count_;
-  std::unique_ptr<mojo::AssociatedInterfacePtr<mojom::Renderer>>
-      renderer_interface_;
+  std::unique_ptr<mojo::AssociatedRemote<mojom::Renderer>> renderer_interface_;
   std::map<std::string, InterfaceBinder> binder_overrides_;
   service_manager::Identity child_identity_;
   bool is_renderer_locked_to_site_ = false;
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index c1d6196..1995097 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -450,6 +450,7 @@
     "//third_party/webrtc/api:callfactory_api",
     "//third_party/webrtc/api:libjingle_logging_api",
     "//third_party/webrtc/api:libjingle_peerconnection_api",
+    "//third_party/webrtc/api:rtc_error",
     "//third_party/webrtc/api:rtc_stats_api",
     "//third_party/webrtc/api:scoped_refptr",
     "//third_party/webrtc/api/audio:aec3_config",
diff --git a/content/renderer/compositor/compositor_dependencies.h b/content/renderer/compositor/compositor_dependencies.h
index a2f87fc2..aa8dbbc7 100644
--- a/content/renderer/compositor/compositor_dependencies.h
+++ b/content/renderer/compositor/compositor_dependencies.h
@@ -12,6 +12,7 @@
 #include "components/viz/common/display/renderer_settings.h"
 #include "content/common/content_export.h"
 #include "content/common/render_frame_metadata.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 
 class GURL;
 
@@ -65,7 +66,8 @@
       LayerTreeFrameSinkCallback callback,
       mojom::RenderFrameMetadataObserverClientRequest
           render_frame_metadata_observer_client_request,
-      mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer_ptr,
+      mojo::PendingRemote<mojom::RenderFrameMetadataObserver>
+          render_frame_metadata_observer_remote,
       const char* client_name) = 0;
 
 #ifdef OS_ANDROID
diff --git a/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.cc
index 066421a..008c53a8 100644
--- a/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.cc
+++ b/content/renderer/media/webrtc/mock_peer_connection_dependency_factory.cc
@@ -326,7 +326,7 @@
 };
 
 MockPeerConnectionDependencyFactory::MockPeerConnectionDependencyFactory()
-    : PeerConnectionDependencyFactory(nullptr),
+    : PeerConnectionDependencyFactory(/*create_p2p_socket_dispatcher =*/false),
       signaling_thread_("MockPCFactory WebRtc Signaling Thread") {
   EnsureWebRtcAudioDeviceImpl();
   CHECK(signaling_thread_.Start());
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
index 74ec380..87bb3347 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -23,7 +23,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "content/public/common/content_client.h"
-#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/webrtc_ip_handling_policy.h"
 #include "content/public/renderer/content_renderer_client.h"
@@ -31,6 +30,7 @@
 #include "content/renderer/p2p/ipc_socket_factory.h"
 #include "content/renderer/p2p/mdns_responder_adapter.h"
 #include "content/renderer/p2p/port_allocator.h"
+#include "content/renderer/p2p/socket_dispatcher.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/render_view_impl.h"
@@ -120,9 +120,10 @@
 }  // namespace
 
 PeerConnectionDependencyFactory::PeerConnectionDependencyFactory(
-    P2PSocketDispatcher* p2p_socket_dispatcher)
+    bool create_p2p_socket_dispatcher)
     : network_manager_(nullptr),
-      p2p_socket_dispatcher_(p2p_socket_dispatcher),
+      p2p_socket_dispatcher_(
+          create_p2p_socket_dispatcher ? new P2PSocketDispatcher() : nullptr),
       signaling_thread_(nullptr),
       worker_thread_(nullptr),
       chrome_signaling_thread_("Chrome_libJingle_Signaling"),
@@ -206,7 +207,8 @@
       base::WaitableEvent::InitialState::NOT_SIGNALED);
   std::unique_ptr<MdnsResponderAdapter> mdns_responder;
 #if BUILDFLAG(ENABLE_MDNS)
-  if (base::FeatureList::IsEnabled(features::kWebRtcHideLocalIpsWithMdns)) {
+  if (base::FeatureList::IsEnabled(
+          blink::features::kWebRtcHideLocalIpsWithMdns)) {
     // Note that MdnsResponderAdapter is created on the main thread to have
     // access to the connector to the service manager.
     mdns_responder = std::make_unique<MdnsResponderAdapter>();
@@ -304,7 +306,7 @@
       blink::CreateWebrtcVideoDecoderFactory(gpu_factories);
 
   // Enable Multiplex codec in SDP optionally.
-  if (base::FeatureList::IsEnabled(features::kWebRtcMultiplexCodec)) {
+  if (base::FeatureList::IsEnabled(blink::features::kWebRtcMultiplexCodec)) {
     webrtc_encoder_factory = std::make_unique<webrtc::MultiplexEncoderFactory>(
         std::move(webrtc_encoder_factory));
     webrtc_decoder_factory = std::make_unique<webrtc::MultiplexDecoderFactory>(
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.h b/content/renderer/media/webrtc/peer_connection_dependency_factory.h
index e77318c4..11e112c 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.h
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.h
@@ -14,7 +14,6 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "content/common/content_export.h"
-#include "content/renderer/p2p/socket_dispatcher.h"
 #include "ipc/ipc_platform_file.h"
 #include "third_party/blink/public/platform/modules/peerconnection/stun_field_trial.h"
 #include "third_party/webrtc/api/peer_connection_interface.h"
@@ -48,12 +47,13 @@
 
 class IpcPacketSocketFactory;
 class MdnsResponderAdapter;
+class P2PSocketDispatcher;
 
 // Object factory for RTC PeerConnections.
 class CONTENT_EXPORT PeerConnectionDependencyFactory
     : base::MessageLoopCurrent::DestructionObserver {
  public:
-  PeerConnectionDependencyFactory(P2PSocketDispatcher* p2p_socket_dispatcher);
+  PeerConnectionDependencyFactory(bool create_p2p_socket_dispatcher);
   ~PeerConnectionDependencyFactory() override;
 
   // Create a RTCPeerConnectionHandler object that implements the
@@ -166,7 +166,9 @@
 
   scoped_refptr<webrtc::PeerConnectionFactoryInterface> pc_factory_;
 
+  // Dispatches all P2P sockets.
   scoped_refptr<P2PSocketDispatcher> p2p_socket_dispatcher_;
+
   scoped_refptr<blink::WebRtcAudioDeviceImpl> audio_device_;
 
   std::unique_ptr<blink::StunProberTrial> stun_trial_;
diff --git a/content/renderer/p2p/host_address_request.cc b/content/renderer/p2p/host_address_request.cc
index 1424c153..1be7da8 100644
--- a/content/renderer/p2p/host_address_request.cc
+++ b/content/renderer/p2p/host_address_request.cc
@@ -10,9 +10,9 @@
 #include "base/feature_list.h"
 #include "base/location.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "content/public/common/content_features.h"
 #include "content/renderer/p2p/socket_dispatcher.h"
 #include "jingle/glue/utils.h"
+#include "third_party/blink/public/common/features.h"
 
 namespace content {
 
@@ -33,8 +33,8 @@
 
   state_ = STATE_SENT;
   done_callback_ = std::move(done_callback);
-  bool enable_mdns =
-      base::FeatureList::IsEnabled(features::kWebRtcHideLocalIpsWithMdns);
+  bool enable_mdns = base::FeatureList::IsEnabled(
+      blink::features::kWebRtcHideLocalIpsWithMdns);
   dispatcher_->GetP2PSocketManager()->get()->GetHostAddress(
       host_name.hostname(), enable_mdns,
       base::BindOnce(&P2PAsyncAddressResolver::OnResponse,
diff --git a/content/renderer/render_frame_metadata_observer_impl.cc b/content/renderer/render_frame_metadata_observer_impl.cc
index 6d72311..58df056 100644
--- a/content/renderer/render_frame_metadata_observer_impl.cc
+++ b/content/renderer/render_frame_metadata_observer_impl.cc
@@ -18,17 +18,15 @@
 }
 
 RenderFrameMetadataObserverImpl::RenderFrameMetadataObserverImpl(
-    mojom::RenderFrameMetadataObserverRequest request,
+    mojo::PendingReceiver<mojom::RenderFrameMetadataObserver> receiver,
     mojom::RenderFrameMetadataObserverClientPtrInfo client_info)
-    : request_(std::move(request)),
-      client_info_(std::move(client_info)),
-      render_frame_metadata_observer_binding_(this) {}
+    : receiver_(std::move(receiver)), client_info_(std::move(client_info)) {}
 
 RenderFrameMetadataObserverImpl::~RenderFrameMetadataObserverImpl() {}
 
 void RenderFrameMetadataObserverImpl::BindToCurrentThread() {
-  DCHECK(request_.is_pending());
-  render_frame_metadata_observer_binding_.Bind(std::move(request_));
+  DCHECK(receiver_.is_valid());
+  render_frame_metadata_observer_receiver_.Bind(std::move(receiver_));
   render_frame_metadata_observer_client_.Bind(std::move(client_info_));
 }
 
diff --git a/content/renderer/render_frame_metadata_observer_impl.h b/content/renderer/render_frame_metadata_observer_impl.h
index c0335ae9..53b565f 100644
--- a/content/renderer/render_frame_metadata_observer_impl.h
+++ b/content/renderer/render_frame_metadata_observer_impl.h
@@ -10,7 +10,8 @@
 #include "cc/trees/render_frame_metadata_observer.h"
 #include "content/common/content_export.h"
 #include "content/common/render_frame_metadata.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 namespace content {
 
@@ -28,7 +29,7 @@
       public mojom::RenderFrameMetadataObserver {
  public:
   RenderFrameMetadataObserverImpl(
-      mojom::RenderFrameMetadataObserverRequest request,
+      mojo::PendingReceiver<mojom::RenderFrameMetadataObserver> receiver,
       mojom::RenderFrameMetadataObserverClientPtrInfo client_info);
   ~RenderFrameMetadataObserverImpl() override;
 
@@ -74,11 +75,11 @@
   base::Optional<cc::RenderFrameMetadata> last_render_frame_metadata_;
 
   // These are destroyed when BindToCurrentThread() is called.
-  mojom::RenderFrameMetadataObserverRequest request_;
+  mojo::PendingReceiver<mojom::RenderFrameMetadataObserver> receiver_;
   mojom::RenderFrameMetadataObserverClientPtrInfo client_info_;
 
-  mojo::Binding<mojom::RenderFrameMetadataObserver>
-      render_frame_metadata_observer_binding_;
+  mojo::Receiver<mojom::RenderFrameMetadataObserver>
+      render_frame_metadata_observer_receiver_{this};
   mojom::RenderFrameMetadataObserverClientPtr
       render_frame_metadata_observer_client_;
 
diff --git a/content/renderer/render_frame_metadata_observer_impl_unittest.cc b/content/renderer/render_frame_metadata_observer_impl_unittest.cc
index e871e72..3663d7a1 100644
--- a/content/renderer/render_frame_metadata_observer_impl_unittest.cc
+++ b/content/renderer/render_frame_metadata_observer_impl_unittest.cc
@@ -11,6 +11,8 @@
 #include "components/viz/common/quads/compositor_frame_metadata.h"
 #include "content/common/render_frame_metadata.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -28,11 +30,11 @@
  public:
   MockRenderFrameMetadataObserverClient(
       mojom::RenderFrameMetadataObserverClientRequest client_request,
-      mojom::RenderFrameMetadataObserverPtr observer)
+      mojo::PendingRemote<mojom::RenderFrameMetadataObserver> observer)
       : render_frame_metadata_observer_client_binding_(
             this,
             std::move(client_request)),
-        render_frame_metadata_observer_ptr_(std::move(observer)) {}
+        render_frame_metadata_observer_remote_(std::move(observer)) {}
 
   MOCK_METHOD2(OnRenderFrameMetadataChanged,
                void(uint32_t frame_token,
@@ -42,7 +44,8 @@
  private:
   mojo::Binding<mojom::RenderFrameMetadataObserverClient>
       render_frame_metadata_observer_client_binding_;
-  mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer_ptr_;
+  mojo::Remote<mojom::RenderFrameMetadataObserver>
+      render_frame_metadata_observer_remote_;
 
   DISALLOW_COPY_AND_ASSIGN(MockRenderFrameMetadataObserverClient);
 };
@@ -58,17 +61,18 @@
 
   // testing::Test:
   void SetUp() override {
-    mojom::RenderFrameMetadataObserverPtr ptr;
-    mojom::RenderFrameMetadataObserverRequest request = mojo::MakeRequest(&ptr);
+    mojo::PendingRemote<mojom::RenderFrameMetadataObserver> observer_remote;
+    mojo::PendingReceiver<mojom::RenderFrameMetadataObserver> receiver =
+        observer_remote.InitWithNewPipeAndPassReceiver();
     mojom::RenderFrameMetadataObserverClientPtrInfo client_info;
     mojom::RenderFrameMetadataObserverClientRequest client_request =
         mojo::MakeRequest(&client_info);
 
     client_ = std::make_unique<
         testing::NiceMock<MockRenderFrameMetadataObserverClient>>(
-        std::move(client_request), std::move(ptr));
+        std::move(client_request), std::move(observer_remote));
     observer_impl_ = std::make_unique<RenderFrameMetadataObserverImpl>(
-        std::move(request), std::move(client_info));
+        std::move(receiver), std::move(client_info));
     observer_impl_->BindToCurrentThread();
   }
 
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 8a220bb..e5fdbd3 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -95,7 +95,6 @@
 #include "content/renderer/media/webrtc/peer_connection_tracker.h"
 #include "content/renderer/media/webrtc/rtc_peer_connection_handler.h"
 #include "content/renderer/net_info_helper.h"
-#include "content/renderer/p2p/socket_dispatcher.h"
 #include "content/renderer/render_frame_proxy.h"
 #include "content/renderer/render_process_impl.h"
 #include "content/renderer/render_view_impl.h"
@@ -122,7 +121,6 @@
 #include "media/base/media_switches.h"
 #include "media/media_buildflags.h"
 #include "media/video/gpu_video_accelerator_factories.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "net/base/net_errors.h"
@@ -677,7 +675,6 @@
                           .Build()),
       main_thread_scheduler_(std::move(scheduler)),
       categorized_worker_pool_(new CategorizedWorkerPool()),
-      renderer_binding_(this),
       client_id_(1),
       compositing_mode_watcher_binding_(this) {
   TRACE_EVENT0("startup", "RenderThreadImpl::Create");
@@ -697,7 +694,6 @@
       main_thread_scheduler_(std::move(scheduler)),
       categorized_worker_pool_(new CategorizedWorkerPool()),
       is_scroll_animator_enabled_(false),
-      renderer_binding_(this),
       compositing_mode_watcher_binding_(this) {
   TRACE_EVENT0("startup", "RenderThreadImpl::Create");
   DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -749,10 +745,8 @@
       new PeerConnectionTracker(main_thread_runner()));
   AddObserver(peer_connection_tracker_.get());
 
-  p2p_socket_dispatcher_ = new P2PSocketDispatcher();
-
-  peer_connection_factory_.reset(
-      new PeerConnectionDependencyFactory(p2p_socket_dispatcher_.get()));
+  peer_connection_factory_.reset(new PeerConnectionDependencyFactory(
+      /*create_p2p_socket_dispatcher =*/true));
 
   unfreezable_message_filter_ = new UnfreezableMessageFilter(this);
   AddFilter(unfreezable_message_filter_.get());
@@ -808,7 +802,7 @@
   StartServiceManagerConnection();
 
   GetAssociatedInterfaceRegistry()->AddInterface(base::BindRepeating(
-      &RenderThreadImpl::OnRendererInterfaceRequest, base::Unretained(this)));
+      &RenderThreadImpl::OnRendererInterfaceReceiver, base::Unretained(this)));
 
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
@@ -1855,7 +1849,8 @@
     LayerTreeFrameSinkCallback callback,
     mojom::RenderFrameMetadataObserverClientRequest
         render_frame_metadata_observer_client_request,
-    mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer_ptr,
+    mojo::PendingRemote<mojom::RenderFrameMetadataObserver>
+        render_frame_metadata_observer_remote,
     const char* client_name) {
   // Misconfigured bots (eg. crbug.com/780757) could run web tests on a
   // machine where gpu compositing doesn't work. Don't crash in that case.
@@ -1908,7 +1903,7 @@
     frame_sink_provider_->RegisterRenderFrameMetadataObserver(
         widget_routing_id,
         std::move(render_frame_metadata_observer_client_request),
-        std::move(render_frame_metadata_observer_ptr));
+        std::move(render_frame_metadata_observer_remote));
     std::move(callback).Run(
         std::make_unique<cc::mojo_embedder::AsyncLayerTreeFrameSink>(
             nullptr, nullptr, &params));
@@ -1971,7 +1966,7 @@
       frame_sink_provider_->RegisterRenderFrameMetadataObserver(
           widget_routing_id,
           std::move(render_frame_metadata_observer_client_request),
-          std::move(render_frame_metadata_observer_ptr));
+          std::move(render_frame_metadata_observer_remote));
 
       std::move(callback).Run(std::make_unique<SynchronousLayerTreeFrameSink>(
           std::move(context_provider), std::move(worker_context_provider),
@@ -1994,7 +1989,7 @@
   frame_sink_provider_->RegisterRenderFrameMetadataObserver(
       widget_routing_id,
       std::move(render_frame_metadata_observer_client_request),
-      std::move(render_frame_metadata_observer_ptr));
+      std::move(render_frame_metadata_observer_remote));
   params.gpu_memory_buffer_manager = GetGpuMemoryBufferManager();
   std::move(callback).Run(
       std::make_unique<cc::mojo_embedder::AsyncLayerTreeFrameSink>(
@@ -2408,11 +2403,11 @@
       v8_memory_pressure_level);
 }
 
-void RenderThreadImpl::OnRendererInterfaceRequest(
-    mojom::RendererAssociatedRequest request) {
-  DCHECK(!renderer_binding_.is_bound());
-  renderer_binding_.Bind(std::move(request),
-                         GetWebMainThreadScheduler()->IPCTaskRunner());
+void RenderThreadImpl::OnRendererInterfaceReceiver(
+    mojo::PendingAssociatedReceiver<mojom::Renderer> receiver) {
+  DCHECK(!renderer_receiver_.is_bound());
+  renderer_receiver_.Bind(std::move(receiver),
+                          GetWebMainThreadScheduler()->IPCTaskRunner());
 }
 
 bool RenderThreadImpl::NeedsToRecordFirstActivePaint(
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 910c91b..54e3c5a 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -44,8 +44,10 @@
 #include "gpu/ipc/client/gpu_channel_host.h"
 #include "ipc/ipc_sync_channel.h"
 #include "media/media_buildflags.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
 #include "net/base/network_change_notifier.h"
@@ -117,7 +119,6 @@
 class CategorizedWorkerPool;
 class GpuVideoAcceleratorFactoriesImpl;
 class LowMemoryModeController;
-class P2PSocketDispatcher;
 class PeerConnectionDependencyFactory;
 class PeerConnectionTracker;
 class RenderThreadObserver;
@@ -239,7 +240,8 @@
       LayerTreeFrameSinkCallback callback,
       mojom::RenderFrameMetadataObserverClientRequest
           render_frame_metadata_observer_client_request,
-      mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer_ptr,
+      mojo::PendingRemote<mojom::RenderFrameMetadataObserver>
+          render_frame_metadata_observer_remote,
       const char* client_name) override;
 #ifdef OS_ANDROID
   bool UsingSynchronousCompositing() override;
@@ -312,11 +314,6 @@
     return peer_connection_tracker_.get();
   }
 
-  // Current P2PSocketDispatcher. Set to NULL if P2P API is disabled.
-  P2PSocketDispatcher* p2p_socket_dispatcher() {
-    return p2p_socket_dispatcher_.get();
-  }
-
   blink::WebVideoCaptureImplManager* video_capture_impl_manager() const {
     return vc_manager_.get();
   }
@@ -565,7 +562,8 @@
   std::unique_ptr<viz::SyntheticBeginFrameSource>
   CreateSyntheticBeginFrameSource();
 
-  void OnRendererInterfaceRequest(mojom::RendererAssociatedRequest request);
+  void OnRendererInterfaceReceiver(
+      mojo::PendingAssociatedReceiver<mojom::Renderer> receiver);
 
   std::unique_ptr<discardable_memory::ClientDiscardableSharedMemoryManager>
       discardable_shared_memory_manager_;
@@ -584,9 +582,6 @@
   // of all the peer connections created in the renderer.
   std::unique_ptr<PeerConnectionTracker> peer_connection_tracker_;
 
-  // Dispatches all P2P sockets.
-  scoped_refptr<P2PSocketDispatcher> p2p_socket_dispatcher_;
-
   // Filter out unfreezable messages and pass it to unfreezable task runners.
   scoped_refptr<UnfreezableMessageFilter> unfreezable_message_filter_;
 
@@ -711,7 +706,7 @@
 
   blink::AssociatedInterfaceRegistry associated_interfaces_;
 
-  mojo::AssociatedBinding<mojom::Renderer> renderer_binding_;
+  mojo::AssociatedReceiver<mojom::Renderer> renderer_receiver_{this};
 
   mojom::RenderMessageFilterAssociatedPtr render_message_filter_;
 
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 746a567f..8e6a8c9 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -78,6 +78,7 @@
 #include "ipc/ipc_sync_message.h"
 #include "ipc/ipc_sync_message_filter.h"
 #include "media/base/media_switches.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "skia/ext/platform_canvas.h"
 #include "third_party/blink/public/platform/file_path_conversion.h"
@@ -1175,14 +1176,14 @@
 
   // TODO(jonross): have this generated by the LayerTreeFrameSink itself, which
   // would then handle binding.
-  mojom::RenderFrameMetadataObserverPtr ptr;
-  mojom::RenderFrameMetadataObserverRequest request = mojo::MakeRequest(&ptr);
+  mojo::PendingRemote<mojom::RenderFrameMetadataObserver> observer_remote;
   mojom::RenderFrameMetadataObserverClientPtrInfo client_info;
   mojom::RenderFrameMetadataObserverClientRequest client_request =
       mojo::MakeRequest(&client_info);
   auto render_frame_metadata_observer =
-      std::make_unique<RenderFrameMetadataObserverImpl>(std::move(request),
-                                                        std::move(client_info));
+      std::make_unique<RenderFrameMetadataObserverImpl>(
+          observer_remote.InitWithNewPipeAndPassReceiver(),
+          std::move(client_info));
   layer_tree_view_->SetRenderFrameObserver(
       std::move(render_frame_metadata_observer));
   GURL url = GetWebWidget()->GetURLForDebugTrace();
@@ -1198,8 +1199,8 @@
   const char* client_name = for_child_local_root_frame_ ? kOOPIF : kRenderer;
   compositor_deps_->RequestNewLayerTreeFrameSink(
       routing_id_, frame_swap_message_queue_, std::move(url),
-      std::move(callback), std::move(client_request), std::move(ptr),
-      client_name);
+      std::move(callback), std::move(client_request),
+      std::move(observer_remote), client_name);
 }
 
 void RenderWidget::DidCommitAndDrawCompositorFrame() {
diff --git a/content/test/data/sxg/ca.cnf b/content/test/data/sxg/ca.cnf
index 04ff0be..6b091b3 100644
--- a/content/test/data/sxg/ca.cnf
+++ b/content/test/data/sxg/ca.cnf
@@ -18,6 +18,7 @@
 # OID required for sxg since d54c469
 1.3.6.1.4.1.11129.2.1.22 = ASN1:NULL
 keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = serverAuth
 subjectKeyIdentifier = hash
 authorityKeyIdentifier = keyid,issuer
 subjectAltName=DNS:test.example.org
diff --git a/content/test/data/sxg/generate-test-certs.sh b/content/test/data/sxg/generate-test-certs.sh
index ae0f148..b011697 100755
--- a/content/test/data/sxg/generate-test-certs.sh
+++ b/content/test/data/sxg/generate-test-certs.sh
@@ -52,13 +52,13 @@
   -in  prime256v1-sha256.csr \
   -out prime256v1-sha256-validity-too-long.public.pem
 
-# Generate a certificate which is valid for 3000 days. It is used in
+# Generate a certificate which is valid for 825 days. It is used in
 # SignedExchangeRequestHandlerRealCertVerifierBrowserTest, where the SXG cert's
 # validity period check is skipped.
 openssl ca -batch \
   -config ca.cnf \
   -extensions sxg_cert \
-  -days 3000 \
+  -days 825 \
   -in  prime256v1-sha256.csr \
   -out prime256v1-sha256-long-validity.public.pem
 
diff --git a/content/test/data/sxg/prime256v1-sha256-long-validity.public.pem b/content/test/data/sxg/prime256v1-sha256-long-validity.public.pem
index 37af7e8..6d2e830 100644
--- a/content/test/data/sxg/prime256v1-sha256-long-validity.public.pem
+++ b/content/test/data/sxg/prime256v1-sha256-long-validity.public.pem
@@ -5,18 +5,18 @@
         Signature Algorithm: sha256WithRSAEncryption
         Issuer: C=US, ST=California, L=Mountain View, O=Test CA, CN=Test Root CA
         Validity
-            Not Before: Aug 30 07:26:06 2019 GMT
-            Not After : Nov 16 07:26:06 2027 GMT
+            Not Before: Sep 10 17:30:38 2019 GMT
+            Not After : Dec 13 17:30:38 2021 GMT
         Subject: CN=test.example.org, O=Test, C=US
         Subject Public Key Info:
             Public Key Algorithm: id-ecPublicKey
                 Public-Key: (256 bit)
                 pub:
-                    04:c3:59:01:23:31:52:9c:c1:ce:1b:09:20:46:a0:
-                    0f:38:03:e8:aa:3c:e3:65:36:52:6c:d7:01:08:49:
-                    70:d7:40:49:73:f6:d7:c8:19:f3:1e:b3:a8:8a:1b:
-                    ae:0b:b6:c8:30:3b:04:9e:58:28:62:1e:db:35:c7:
-                    e3:15:60:ac:fb
+                    04:56:24:49:7a:0a:a9:df:1a:0a:07:e3:ad:2a:23:
+                    6d:e9:33:25:68:5a:96:33:03:95:13:26:d9:44:ff:
+                    a8:59:16:6d:b6:7d:50:74:6e:d9:f7:9d:48:b2:61:
+                    ba:f8:6a:1e:fe:c6:1b:83:09:7f:84:9a:56:4f:68:
+                    a8:3e:28:d1:10
                 ASN1 OID: prime256v1
                 NIST CURVE: P-256
         X509v3 extensions:
@@ -26,44 +26,46 @@
                 ..
             X509v3 Key Usage: 
                 Digital Signature, Non Repudiation, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication
             X509v3 Subject Key Identifier: 
-                2C:8C:A1:2C:69:E4:1A:28:9C:2B:02:15:ED:62:9F:39:1D:49:D7:66
+                81:00:BA:FD:50:89:3A:F4:C7:7E:72:35:0A:53:4B:64:5F:02:02:7D
             X509v3 Authority Key Identifier: 
                 keyid:9B:26:0B:8A:98:A9:BB:1D:B9:1F:1C:E3:1A:40:33:ED:8E:17:88:AB
 
             X509v3 Subject Alternative Name: 
                 DNS:test.example.org
     Signature Algorithm: sha256WithRSAEncryption
-         0f:6b:23:a8:7e:cf:f0:ac:bb:9b:7d:ab:dd:c2:e3:18:63:db:
-         a3:7b:1f:e9:00:89:65:bf:e7:f8:93:a4:78:7c:1e:f3:bc:8c:
-         d0:d6:d7:32:d4:87:a5:eb:f3:9e:df:be:7f:35:af:2d:21:4b:
-         86:e0:90:74:57:be:45:54:c2:e2:80:e3:9b:ab:fe:be:ff:a4:
-         ef:fd:f1:d7:e7:24:7c:13:d4:24:35:9e:87:5b:d1:dd:18:2f:
-         c9:22:a6:e4:b3:2c:6e:a2:25:fb:c2:42:27:41:2c:53:f7:cd:
-         3d:57:bf:1e:42:26:3e:ae:ec:43:b6:af:1e:9b:a3:a7:2b:fc:
-         4f:fb:ab:a8:79:a1:01:69:f6:68:bd:a3:c7:5c:0e:06:4f:1d:
-         79:db:be:57:3b:17:81:13:ed:f8:5b:f2:b6:ee:51:3a:98:2b:
-         94:42:3f:75:44:c2:5e:08:88:7e:b8:1f:bc:02:76:9a:c9:61:
-         a6:92:12:1d:06:97:dd:d2:3e:e8:d9:1c:08:07:bc:15:32:cd:
-         27:b1:64:13:3d:4a:69:ec:82:3f:b8:5c:f6:38:73:c2:af:bf:
-         a7:d5:a3:03:5c:62:98:46:a3:8b:77:0f:4c:4a:ba:ab:94:9c:
-         8d:7a:11:90:bf:ca:07:0f:b7:e5:3b:9d:91:df:54:09:b9:b1:
-         11:c3:68:6f
+         aa:c6:30:cf:6a:28:59:5a:ab:ab:f4:ad:e4:31:5c:e4:e0:95:
+         9e:43:92:84:73:bb:18:f7:f9:f6:ef:ec:d2:68:01:7b:d2:87:
+         0d:30:7d:13:8b:fa:42:6b:1e:ec:b7:df:a1:9a:b6:ad:23:8d:
+         34:74:a6:a4:e3:0c:5f:eb:7a:12:c6:e7:fd:81:5f:40:29:1a:
+         5b:00:9c:35:b5:5a:47:29:1f:7a:4b:a9:95:3c:01:b0:cc:0e:
+         9d:c5:74:b5:e3:17:d5:ac:4b:86:ab:37:ba:0c:ff:6e:87:d9:
+         8c:eb:45:83:01:63:04:08:eb:9b:cb:23:8f:ce:12:79:71:e4:
+         64:8c:63:14:17:2d:30:e1:fa:1b:63:89:33:f6:35:96:09:8a:
+         5b:21:c3:c8:40:d8:be:95:a7:13:29:fb:da:96:83:e3:0f:b2:
+         ee:8b:39:05:2d:0b:34:31:e0:e7:e2:b2:e7:76:c8:79:a1:0d:
+         68:72:82:20:ab:ea:6a:5e:2b:9d:a9:0e:52:be:1e:6f:ba:e0:
+         dd:3b:24:d2:d8:9a:8f:f8:71:81:14:ab:e4:71:8a:20:f9:f0:
+         66:ad:dd:da:a9:bf:83:ad:49:3c:13:84:05:d1:b8:1b:23:5e:
+         e4:e1:1b:65:9e:da:49:1b:1d:0e:b2:ba:03:25:ca:21:6b:32:
+         a5:7e:49:85
 -----BEGIN CERTIFICATE-----
-MIIC1TCCAb2gAwIBAgIBBDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzET
+MIIC6jCCAdKgAwIBAgIBBDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzET
 MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G
-A1UECgwHVGVzdCBDQTEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTE5MDgzMDA3
-MjYwNloXDTI3MTExNjA3MjYwNlowNzEZMBcGA1UEAwwQdGVzdC5leGFtcGxlLm9y
+A1UECgwHVGVzdCBDQTEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTE5MDkxMDE3
+MzAzOFoXDTIxMTIxMzE3MzAzOFowNzEZMBcGA1UEAwwQdGVzdC5leGFtcGxlLm9y
 ZzENMAsGA1UECgwEVGVzdDELMAkGA1UEBhMCVVMwWTATBgcqhkjOPQIBBggqhkjO
-PQMBBwNCAATDWQEjMVKcwc4bCSBGoA84A+iqPONlNlJs1wEISXDXQElz9tfIGfMe
-s6iKG64LtsgwOwSeWChiHts1x+MVYKz7o4GKMIGHMAkGA1UdEwQCMAAwEAYKKwYB
-BAHWeQIBFgQCBQAwCwYDVR0PBAQDAgXgMB0GA1UdDgQWBBQsjKEsaeQaKJwrAhXt
-Yp85HUnXZjAfBgNVHSMEGDAWgBSbJguKmKm7HbkfHOMaQDPtjheIqzAbBgNVHREE
-FDASghB0ZXN0LmV4YW1wbGUub3JnMA0GCSqGSIb3DQEBCwUAA4IBAQAPayOofs/w
-rLubfavdwuMYY9ujex/pAIllv+f4k6R4fB7zvIzQ1tcy1Iel6/Oe375/Na8tIUuG
-4JB0V75FVMLigOObq/6+/6Tv/fHX5yR8E9QkNZ6HW9HdGC/JIqbksyxuoiX7wkIn
-QSxT9809V78eQiY+ruxDtq8em6OnK/xP+6uoeaEBafZovaPHXA4GTx15275XOxeB
-E+34W/K27lE6mCuUQj91RMJeCIh+uB+8AnaayWGmkhIdBpfd0j7o2RwIB7wVMs0n
-sWQTPUpp7II/uFz2OHPCr7+n1aMDXGKYRqOLdw9MSrqrlJyNehGQv8oHD7flO52R
-31QJubERw2hv
+PQMBBwNCAARWJEl6CqnfGgoH460qI23pMyVoWpYzA5UTJtlE/6hZFm22fVB0btn3
+nUiyYbr4ah7+xhuDCX+EmlZPaKg+KNEQo4GfMIGcMAkGA1UdEwQCMAAwEAYKKwYB
+BAHWeQIBFgQCBQAwCwYDVR0PBAQDAgXgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0G
+A1UdDgQWBBSBALr9UIk69Md+cjUKU0tkXwICfTAfBgNVHSMEGDAWgBSbJguKmKm7
+HbkfHOMaQDPtjheIqzAbBgNVHREEFDASghB0ZXN0LmV4YW1wbGUub3JnMA0GCSqG
+SIb3DQEBCwUAA4IBAQCqxjDPaihZWqur9K3kMVzk4JWeQ5KEc7sY9/n27+zSaAF7
+0ocNMH0Ti/pCax7st9+hmratI400dKak4wxf63oSxuf9gV9AKRpbAJw1tVpHKR96
+S6mVPAGwzA6dxXS14xfVrEuGqze6DP9uh9mM60WDAWMECOubyyOPzhJ5ceRkjGMU
+Fy0w4fobY4kz9jWWCYpbIcPIQNi+lacTKfvaloPjD7LuizkFLQs0MeDn4rLndsh5
+oQ1ocoIgq+pqXiudqQ5Svh5vuuDdOyTS2JqP+HGBFKvkcYog+fBmrd3aqb+DrUk8
+E4QF0bgbI17k4RtlntpJGx0OsroDJcohazKlfkmF
 -----END CERTIFICATE-----
diff --git a/content/test/data/sxg/prime256v1-sha256-noext.public.pem b/content/test/data/sxg/prime256v1-sha256-noext.public.pem
index a7839fcb..56e76728 100644
--- a/content/test/data/sxg/prime256v1-sha256-noext.public.pem
+++ b/content/test/data/sxg/prime256v1-sha256-noext.public.pem
@@ -12,41 +12,41 @@
             Public Key Algorithm: id-ecPublicKey
                 Public-Key: (256 bit)
                 pub:
-                    04:c3:59:01:23:31:52:9c:c1:ce:1b:09:20:46:a0:
-                    0f:38:03:e8:aa:3c:e3:65:36:52:6c:d7:01:08:49:
-                    70:d7:40:49:73:f6:d7:c8:19:f3:1e:b3:a8:8a:1b:
-                    ae:0b:b6:c8:30:3b:04:9e:58:28:62:1e:db:35:c7:
-                    e3:15:60:ac:fb
+                    04:56:24:49:7a:0a:a9:df:1a:0a:07:e3:ad:2a:23:
+                    6d:e9:33:25:68:5a:96:33:03:95:13:26:d9:44:ff:
+                    a8:59:16:6d:b6:7d:50:74:6e:d9:f7:9d:48:b2:61:
+                    ba:f8:6a:1e:fe:c6:1b:83:09:7f:84:9a:56:4f:68:
+                    a8:3e:28:d1:10
                 ASN1 OID: prime256v1
                 NIST CURVE: P-256
     Signature Algorithm: sha256WithRSAEncryption
-         54:82:c9:27:33:0e:95:af:18:7b:a7:cb:1f:53:86:aa:08:38:
-         c2:60:58:66:60:6d:de:ae:a0:68:e5:5a:03:fd:3c:7b:0d:0a:
-         24:bb:d3:58:13:3f:c1:47:21:43:83:77:07:88:c2:04:23:87:
-         00:17:ad:2d:df:86:5f:d6:61:bb:18:ed:99:06:44:45:b7:df:
-         02:b3:c7:c8:2a:80:48:62:57:5d:15:74:13:07:e6:96:01:3a:
-         eb:82:67:c3:54:96:e3:ea:a5:ed:30:28:d6:55:2d:67:0b:ac:
-         4e:87:ca:5c:93:fc:a8:ae:a2:ec:5f:b4:31:50:1e:ba:2a:a3:
-         35:18:09:d9:68:8a:e2:3a:25:28:82:c3:56:c8:4f:14:6b:81:
-         90:82:af:73:6d:10:17:47:32:6e:bd:45:5f:6f:cb:b7:56:44:
-         df:ae:3b:e3:b2:d1:e4:3b:da:c9:34:ef:36:ca:14:28:cf:98:
-         9b:24:53:64:8f:b1:dc:83:a0:39:60:ce:08:13:40:59:fd:19:
-         a3:ec:d9:1e:17:89:5b:ff:ff:49:07:5e:4c:a8:91:85:e4:fd:
-         b4:51:78:c4:bc:25:95:a7:4a:59:43:3d:53:20:ac:b1:d2:89:
-         12:f9:86:e3:55:16:d2:3d:77:20:4d:38:f2:07:dd:6a:d3:da:
-         f8:e2:ff:36
+         21:c1:39:a8:ba:d2:a5:ac:dd:a3:f5:00:24:cb:36:c3:80:0a:
+         32:f2:e1:7d:98:d3:43:44:75:80:15:6f:2a:63:88:0d:9d:f9:
+         ec:77:b5:0f:c6:0c:d8:32:00:95:4b:f4:0c:49:40:a4:7f:ba:
+         9f:f3:e0:65:c6:22:9f:c8:5b:ac:e6:5e:49:11:57:aa:ab:a2:
+         74:9d:d0:8a:7d:40:05:c1:8f:62:97:d2:f4:a4:7d:a6:20:60:
+         39:8c:eb:18:a7:28:5e:c8:66:b7:37:ea:10:ac:50:cc:14:69:
+         ac:1a:68:f6:be:56:19:db:08:15:2b:4e:64:3a:7b:82:ee:5e:
+         c9:5d:4f:b6:67:32:77:e5:b8:9d:00:16:5b:e6:18:d4:cd:b4:
+         92:1d:f2:47:a7:af:97:f3:ac:d2:8b:88:58:ba:3a:3a:2c:ff:
+         bf:79:b1:a0:c9:d6:b0:69:ce:68:d6:c3:2e:66:69:0b:8c:7a:
+         49:3f:9c:4a:e8:5f:f2:80:fb:cb:44:2c:7c:50:8a:db:24:6a:
+         26:a8:ea:6f:55:2c:ba:13:60:02:05:87:69:b9:b8:ce:99:a1:
+         ca:a6:45:00:26:a4:15:53:d2:28:f3:3c:28:2a:4c:17:65:b4:
+         50:e5:45:73:44:32:50:20:b1:c7:45:a1:e8:d2:3e:1d:d2:82:
+         5a:b7:42:ad
 -----BEGIN CERTIFICATE-----
 MIICQzCCASsCAQIwDQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMxEzARBgNV
 BAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoM
 B1Rlc3QgQ0ExFTATBgNVBAMMDFRlc3QgUm9vdCBDQTAeFw0xOTA2MDEwMDAwMDBa
 Fw0xOTA4MzAwMDAwMDBaMDcxGTAXBgNVBAMMEHRlc3QuZXhhbXBsZS5vcmcxDTAL
 BgNVBAoMBFRlc3QxCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD
-QgAEw1kBIzFSnMHOGwkgRqAPOAPoqjzjZTZSbNcBCElw10BJc/bXyBnzHrOoihuu
-C7bIMDsEnlgoYh7bNcfjFWCs+zANBgkqhkiG9w0BAQsFAAOCAQEAVILJJzMOla8Y
-e6fLH1OGqgg4wmBYZmBt3q6gaOVaA/08ew0KJLvTWBM/wUchQ4N3B4jCBCOHABet
-Ld+GX9ZhuxjtmQZERbffArPHyCqASGJXXRV0EwfmlgE664Jnw1SW4+ql7TAo1lUt
-ZwusTofKXJP8qK6i7F+0MVAeuiqjNRgJ2WiK4jolKILDVshPFGuBkIKvc20QF0cy
-br1FX2/Lt1ZE364747LR5DvayTTvNsoUKM+YmyRTZI+x3IOgOWDOCBNAWf0Zo+zZ
-HheJW///SQdeTKiRheT9tFF4xLwlladKWUM9UyCssdKJEvmG41UW0j13IE048gfd
-atPa+OL/Ng==
+QgAEViRJegqp3xoKB+OtKiNt6TMlaFqWMwOVEybZRP+oWRZttn1QdG7Z951IsmG6
++Goe/sYbgwl/hJpWT2ioPijREDANBgkqhkiG9w0BAQsFAAOCAQEAIcE5qLrSpazd
+o/UAJMs2w4AKMvLhfZjTQ0R1gBVvKmOIDZ357He1D8YM2DIAlUv0DElApH+6n/Pg
+ZcYin8hbrOZeSRFXqquidJ3Qin1ABcGPYpfS9KR9piBgOYzrGKcoXshmtzfqEKxQ
+zBRprBpo9r5WGdsIFStOZDp7gu5eyV1Ptmcyd+W4nQAWW+YY1M20kh3yR6evl/Os
+0ouIWLo6Oiz/v3mxoMnWsGnOaNbDLmZpC4x6ST+cSuhf8oD7y0QsfFCK2yRqJqjq
+b1UsuhNgAgWHabm4zpmhyqZFACakFVPSKPM8KCpMF2W0UOVFc0QyUCCxx0Wh6NI+
+HdKCWrdCrQ==
 -----END CERTIFICATE-----
diff --git a/content/test/data/sxg/prime256v1-sha256-validity-too-long.public.pem b/content/test/data/sxg/prime256v1-sha256-validity-too-long.public.pem
index 918ce8d..85b0d6d 100644
--- a/content/test/data/sxg/prime256v1-sha256-validity-too-long.public.pem
+++ b/content/test/data/sxg/prime256v1-sha256-validity-too-long.public.pem
@@ -12,11 +12,11 @@
             Public Key Algorithm: id-ecPublicKey
                 Public-Key: (256 bit)
                 pub:
-                    04:c3:59:01:23:31:52:9c:c1:ce:1b:09:20:46:a0:
-                    0f:38:03:e8:aa:3c:e3:65:36:52:6c:d7:01:08:49:
-                    70:d7:40:49:73:f6:d7:c8:19:f3:1e:b3:a8:8a:1b:
-                    ae:0b:b6:c8:30:3b:04:9e:58:28:62:1e:db:35:c7:
-                    e3:15:60:ac:fb
+                    04:56:24:49:7a:0a:a9:df:1a:0a:07:e3:ad:2a:23:
+                    6d:e9:33:25:68:5a:96:33:03:95:13:26:d9:44:ff:
+                    a8:59:16:6d:b6:7d:50:74:6e:d9:f7:9d:48:b2:61:
+                    ba:f8:6a:1e:fe:c6:1b:83:09:7f:84:9a:56:4f:68:
+                    a8:3e:28:d1:10
                 ASN1 OID: prime256v1
                 NIST CURVE: P-256
         X509v3 extensions:
@@ -26,44 +26,46 @@
                 ..
             X509v3 Key Usage: 
                 Digital Signature, Non Repudiation, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication
             X509v3 Subject Key Identifier: 
-                2C:8C:A1:2C:69:E4:1A:28:9C:2B:02:15:ED:62:9F:39:1D:49:D7:66
+                81:00:BA:FD:50:89:3A:F4:C7:7E:72:35:0A:53:4B:64:5F:02:02:7D
             X509v3 Authority Key Identifier: 
                 keyid:9B:26:0B:8A:98:A9:BB:1D:B9:1F:1C:E3:1A:40:33:ED:8E:17:88:AB
 
             X509v3 Subject Alternative Name: 
                 DNS:test.example.org
     Signature Algorithm: sha256WithRSAEncryption
-         64:5d:7a:eb:73:2b:6d:58:bc:31:d5:63:33:b3:2c:96:a2:1e:
-         93:46:dd:17:40:1a:ed:ee:12:49:b3:90:46:aa:fe:26:c9:fa:
-         f8:dc:a1:30:83:2a:0a:b1:80:b9:4b:0c:cb:10:ce:02:11:4e:
-         fb:5b:57:1a:f8:e9:55:77:56:3b:ef:19:07:e6:a5:18:e8:63:
-         1f:95:ce:43:a4:15:b2:cd:fb:54:67:cc:c2:86:14:17:ac:ac:
-         16:aa:a8:23:0e:f7:41:3b:2e:7b:7c:7c:f8:56:36:96:2d:d3:
-         19:20:6b:d4:aa:7a:31:aa:ca:8b:f6:15:ac:d3:a4:1c:36:73:
-         24:b6:4d:54:bf:f4:69:4c:cc:05:01:9f:ec:6c:97:63:8c:a0:
-         57:a9:5c:bd:45:f3:75:6f:e1:3d:0d:86:66:ed:0d:f2:07:d4:
-         0c:b8:89:31:1d:b8:17:b5:a8:18:f5:10:51:24:5b:6b:23:cf:
-         40:0e:fc:a0:c5:30:31:52:2d:d4:9a:66:ba:04:a0:bf:4b:5b:
-         6e:87:5f:f1:da:a8:3a:74:ec:bc:cf:e1:95:9a:b7:6d:26:d1:
-         8d:74:86:e3:02:97:08:2c:e5:f3:e9:4a:0f:89:27:e6:68:b7:
-         97:1f:b2:b2:b3:df:1e:3f:ad:c2:0e:57:5c:f1:80:27:0b:ec:
-         1a:cb:97:b8
+         6d:d8:47:dd:13:c8:7f:06:db:71:a1:ca:d3:ca:48:b7:16:8b:
+         b3:b8:c5:d0:73:16:d8:e2:ba:9e:fb:89:da:1a:21:f7:8c:46:
+         30:e7:26:21:94:7e:53:d7:04:0b:95:fa:df:4a:65:85:5e:bb:
+         80:43:03:62:71:3c:f7:7f:aa:06:da:7c:c7:0c:14:bf:92:7e:
+         b4:d0:0b:81:2d:de:2a:a9:99:40:e3:86:da:ee:4b:61:0c:81:
+         75:67:da:55:8e:4b:38:00:60:17:b0:9b:1a:d9:a2:74:8f:ac:
+         e8:4d:24:7c:91:ae:41:50:7a:27:e6:da:5f:92:57:6f:9b:3a:
+         ca:cd:5c:ec:55:f4:50:c9:13:c2:f3:0a:4f:53:8e:32:2b:7f:
+         0e:c9:f1:bb:7b:f0:74:e0:96:d4:e1:de:4b:37:8c:f5:97:de:
+         61:d2:b2:fe:77:97:fa:a2:f2:fb:d9:26:da:6b:cd:f3:68:1a:
+         d0:1d:24:aa:e9:e1:32:71:3a:41:fb:00:27:03:23:5b:25:6f:
+         19:bd:27:42:bb:ba:34:4e:9d:19:dc:65:e9:79:67:71:fa:28:
+         d7:97:a4:f1:5a:96:42:f9:5f:07:df:95:26:43:ff:25:62:43:
+         9b:c7:a2:04:7e:d6:87:a8:a5:b7:1c:e7:0a:aa:19:b5:fe:2f:
+         c0:1e:55:cc
 -----BEGIN CERTIFICATE-----
-MIIC1TCCAb2gAwIBAgIBAzANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzET
+MIIC6jCCAdKgAwIBAgIBAzANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzET
 MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G
 A1UECgwHVGVzdCBDQTEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTE5MDUwMTAw
 MDAwMFoXDTE5MDczMTAwMDAwMFowNzEZMBcGA1UEAwwQdGVzdC5leGFtcGxlLm9y
 ZzENMAsGA1UECgwEVGVzdDELMAkGA1UEBhMCVVMwWTATBgcqhkjOPQIBBggqhkjO
-PQMBBwNCAATDWQEjMVKcwc4bCSBGoA84A+iqPONlNlJs1wEISXDXQElz9tfIGfMe
-s6iKG64LtsgwOwSeWChiHts1x+MVYKz7o4GKMIGHMAkGA1UdEwQCMAAwEAYKKwYB
-BAHWeQIBFgQCBQAwCwYDVR0PBAQDAgXgMB0GA1UdDgQWBBQsjKEsaeQaKJwrAhXt
-Yp85HUnXZjAfBgNVHSMEGDAWgBSbJguKmKm7HbkfHOMaQDPtjheIqzAbBgNVHREE
-FDASghB0ZXN0LmV4YW1wbGUub3JnMA0GCSqGSIb3DQEBCwUAA4IBAQBkXXrrcytt
-WLwx1WMzsyyWoh6TRt0XQBrt7hJJs5BGqv4myfr43KEwgyoKsYC5SwzLEM4CEU77
-W1ca+OlVd1Y77xkH5qUY6GMflc5DpBWyzftUZ8zChhQXrKwWqqgjDvdBOy57fHz4
-VjaWLdMZIGvUqnoxqsqL9hWs06QcNnMktk1Uv/RpTMwFAZ/sbJdjjKBXqVy9RfN1
-b+E9DYZm7Q3yB9QMuIkxHbgXtagY9RBRJFtrI89ADvygxTAxUi3Umma6BKC/S1tu
-h1/x2qg6dOy8z+GVmrdtJtGNdIbjApcILOXz6UoPiSfmaLeXH7Kys98eP63CDldc
-8YAnC+way5e4
+PQMBBwNCAARWJEl6CqnfGgoH460qI23pMyVoWpYzA5UTJtlE/6hZFm22fVB0btn3
+nUiyYbr4ah7+xhuDCX+EmlZPaKg+KNEQo4GfMIGcMAkGA1UdEwQCMAAwEAYKKwYB
+BAHWeQIBFgQCBQAwCwYDVR0PBAQDAgXgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0G
+A1UdDgQWBBSBALr9UIk69Md+cjUKU0tkXwICfTAfBgNVHSMEGDAWgBSbJguKmKm7
+HbkfHOMaQDPtjheIqzAbBgNVHREEFDASghB0ZXN0LmV4YW1wbGUub3JnMA0GCSqG
+SIb3DQEBCwUAA4IBAQBt2EfdE8h/BttxocrTyki3FouzuMXQcxbY4rqe+4naGiH3
+jEYw5yYhlH5T1wQLlfrfSmWFXruAQwNicTz3f6oG2nzHDBS/kn600AuBLd4qqZlA
+44ba7kthDIF1Z9pVjks4AGAXsJsa2aJ0j6zoTSR8ka5BUHon5tpfkldvmzrKzVzs
+VfRQyRPC8wpPU44yK38OyfG7e/B04JbU4d5LN4z1l95h0rL+d5f6ovL72Sbaa83z
+aBrQHSSq6eEycTpB+wAnAyNbJW8ZvSdCu7o0Tp0Z3GXpeWdx+ijXl6TxWpZC+V8H
+35UmQ/8lYkObx6IEftaHqKW3HOcKqhm1/i/AHlXM
 -----END CERTIFICATE-----
diff --git a/content/test/data/sxg/prime256v1-sha256.csr b/content/test/data/sxg/prime256v1-sha256.csr
index 0f9fdb3..5382a1c 100644
--- a/content/test/data/sxg/prime256v1-sha256.csr
+++ b/content/test/data/sxg/prime256v1-sha256.csr
@@ -1,8 +1,8 @@
 -----BEGIN CERTIFICATE REQUEST-----
 MIHyMIGZAgEAMDcxGTAXBgNVBAMMEHRlc3QuZXhhbXBsZS5vcmcxDTALBgNVBAoM
-BFRlc3QxCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEw1kB
-IzFSnMHOGwkgRqAPOAPoqjzjZTZSbNcBCElw10BJc/bXyBnzHrOoihuuC7bIMDsE
-nlgoYh7bNcfjFWCs+6AAMAoGCCqGSM49BAMCA0gAMEUCIQCDSaD4cDigAkxKWiko
-PRO/1JH6RMTB8cRA0ckhlKGvYQIgOTtyfIcaZjX9cqO7rx7GmXtp0Ekb6iMcBo1n
-+4x8oGo=
+BFRlc3QxCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEViRJ
+egqp3xoKB+OtKiNt6TMlaFqWMwOVEybZRP+oWRZttn1QdG7Z951IsmG6+Goe/sYb
+gwl/hJpWT2ioPijREKAAMAoGCCqGSM49BAMCA0gAMEUCIQD0E7nJvlMXoDembcQv
+BxrArv3zWZP0/2BL1rZKuszDVQIgfZkoHFDQcmd+D7/opKRqd42hHMbKvKAJZraN
+/U0Z54Y=
 -----END CERTIFICATE REQUEST-----
diff --git a/content/test/data/sxg/prime256v1-sha256.public.pem b/content/test/data/sxg/prime256v1-sha256.public.pem
index 30e14e0..4ef0c073 100644
--- a/content/test/data/sxg/prime256v1-sha256.public.pem
+++ b/content/test/data/sxg/prime256v1-sha256.public.pem
@@ -12,11 +12,11 @@
             Public Key Algorithm: id-ecPublicKey
                 Public-Key: (256 bit)
                 pub:
-                    04:c3:59:01:23:31:52:9c:c1:ce:1b:09:20:46:a0:
-                    0f:38:03:e8:aa:3c:e3:65:36:52:6c:d7:01:08:49:
-                    70:d7:40:49:73:f6:d7:c8:19:f3:1e:b3:a8:8a:1b:
-                    ae:0b:b6:c8:30:3b:04:9e:58:28:62:1e:db:35:c7:
-                    e3:15:60:ac:fb
+                    04:56:24:49:7a:0a:a9:df:1a:0a:07:e3:ad:2a:23:
+                    6d:e9:33:25:68:5a:96:33:03:95:13:26:d9:44:ff:
+                    a8:59:16:6d:b6:7d:50:74:6e:d9:f7:9d:48:b2:61:
+                    ba:f8:6a:1e:fe:c6:1b:83:09:7f:84:9a:56:4f:68:
+                    a8:3e:28:d1:10
                 ASN1 OID: prime256v1
                 NIST CURVE: P-256
         X509v3 extensions:
@@ -26,44 +26,46 @@
                 ..
             X509v3 Key Usage: 
                 Digital Signature, Non Repudiation, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication
             X509v3 Subject Key Identifier: 
-                2C:8C:A1:2C:69:E4:1A:28:9C:2B:02:15:ED:62:9F:39:1D:49:D7:66
+                81:00:BA:FD:50:89:3A:F4:C7:7E:72:35:0A:53:4B:64:5F:02:02:7D
             X509v3 Authority Key Identifier: 
                 keyid:9B:26:0B:8A:98:A9:BB:1D:B9:1F:1C:E3:1A:40:33:ED:8E:17:88:AB
 
             X509v3 Subject Alternative Name: 
                 DNS:test.example.org
     Signature Algorithm: sha256WithRSAEncryption
-         a2:b7:e4:08:a4:d6:6e:df:65:85:e4:b6:a6:d9:e8:65:c9:9e:
-         43:d0:26:18:04:ca:f7:6c:c1:b7:d9:76:04:bf:4c:63:4f:ff:
-         91:d4:ca:57:d0:b4:58:15:03:f8:94:2d:a0:fe:ee:60:d0:e4:
-         c6:0e:3f:bd:10:50:28:43:5f:64:d2:58:4f:ed:8c:16:82:e2:
-         00:94:a6:f8:91:ac:97:10:1b:62:5e:ca:62:10:f4:6f:84:31:
-         14:12:b5:eb:af:e7:40:9f:54:e4:ba:21:df:ae:81:8c:59:f8:
-         c7:f3:28:88:70:61:09:20:cf:93:96:70:3e:6f:be:e2:06:6c:
-         40:05:bb:29:05:9d:12:6c:87:08:11:cd:1a:96:84:7e:1d:0b:
-         fa:68:ce:fe:ff:e8:e5:96:cd:e4:58:eb:0f:c7:f5:40:13:18:
-         12:15:68:e0:8f:14:f0:a1:e7:6b:e3:83:14:e7:f7:c6:aa:5a:
-         0a:82:8b:c7:f2:76:45:f2:6d:dd:d9:a8:c8:31:43:58:ab:e1:
-         67:57:69:df:bf:ae:cc:c1:bb:3d:02:b5:3f:97:87:e9:35:58:
-         7b:70:49:86:33:e3:a3:09:be:78:c2:e3:a1:6b:0b:b2:17:fe:
-         31:ad:4c:46:06:39:bd:37:45:d5:d0:66:2a:fc:0f:73:2e:83:
-         d2:8f:19:90
+         1e:dd:53:10:3d:08:8a:b7:38:63:3a:67:2c:62:f9:70:65:dd:
+         7d:67:7c:40:8e:ff:aa:3a:2c:75:69:87:3e:f7:3d:9d:99:4f:
+         df:85:3b:10:54:44:2d:f5:3d:bf:ff:3a:8d:49:ba:08:cb:3e:
+         10:ba:9f:4f:05:a0:68:ab:75:78:84:c7:0a:b6:f2:e2:d5:82:
+         a7:eb:87:7c:14:07:4f:68:cb:24:f8:9d:34:cc:56:be:6b:56:
+         44:0a:eb:cf:f4:35:27:32:cf:3a:6e:37:9b:8c:fb:fe:4f:d2:
+         37:74:86:e8:93:a8:27:51:e1:f3:87:f2:4f:b7:c9:d8:0e:f0:
+         7d:53:3f:cb:34:9e:5c:6e:84:bc:65:fb:74:a0:80:d1:ea:c4:
+         2a:c3:d5:a4:e2:b0:8d:ca:c1:6c:a3:34:f8:5a:33:de:a9:e0:
+         a8:a5:3d:6b:72:e4:52:4b:f9:bd:42:74:c6:47:54:80:67:81:
+         36:ee:f1:ff:2a:bf:da:f3:a6:dc:12:f7:b9:41:72:4a:aa:14:
+         9b:f5:d5:b5:b8:e4:73:37:03:97:55:0a:c5:89:f6:c5:d2:0c:
+         7f:fc:de:4e:f6:fd:dd:8f:27:52:c8:57:b4:f1:cf:57:45:23:
+         b9:45:38:ee:92:61:56:16:82:da:41:5e:70:f2:3b:2e:38:f8:
+         ee:a9:ce:fe
 -----BEGIN CERTIFICATE-----
-MIIC1TCCAb2gAwIBAgIBATANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzET
+MIIC6jCCAdKgAwIBAgIBATANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzET
 MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G
 A1UECgwHVGVzdCBDQTEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTE5MDYwMTAw
 MDAwMFoXDTE5MDgzMDAwMDAwMFowNzEZMBcGA1UEAwwQdGVzdC5leGFtcGxlLm9y
 ZzENMAsGA1UECgwEVGVzdDELMAkGA1UEBhMCVVMwWTATBgcqhkjOPQIBBggqhkjO
-PQMBBwNCAATDWQEjMVKcwc4bCSBGoA84A+iqPONlNlJs1wEISXDXQElz9tfIGfMe
-s6iKG64LtsgwOwSeWChiHts1x+MVYKz7o4GKMIGHMAkGA1UdEwQCMAAwEAYKKwYB
-BAHWeQIBFgQCBQAwCwYDVR0PBAQDAgXgMB0GA1UdDgQWBBQsjKEsaeQaKJwrAhXt
-Yp85HUnXZjAfBgNVHSMEGDAWgBSbJguKmKm7HbkfHOMaQDPtjheIqzAbBgNVHREE
-FDASghB0ZXN0LmV4YW1wbGUub3JnMA0GCSqGSIb3DQEBCwUAA4IBAQCit+QIpNZu
-32WF5Lam2ehlyZ5D0CYYBMr3bMG32XYEv0xjT/+R1MpX0LRYFQP4lC2g/u5g0OTG
-Dj+9EFAoQ19k0lhP7YwWguIAlKb4kayXEBtiXspiEPRvhDEUErXrr+dAn1TkuiHf
-roGMWfjH8yiIcGEJIM+TlnA+b77iBmxABbspBZ0SbIcIEc0aloR+HQv6aM7+/+jl
-ls3kWOsPx/VAExgSFWjgjxTwoedr44MU5/fGqloKgovH8nZF8m3d2ajIMUNYq+Fn
-V2nfv67Mwbs9ArU/l4fpNVh7cEmGM+OjCb54wuOhawuyF/4xrUxGBjm9N0XV0GYq
-/A9zLoPSjxmQ
+PQMBBwNCAARWJEl6CqnfGgoH460qI23pMyVoWpYzA5UTJtlE/6hZFm22fVB0btn3
+nUiyYbr4ah7+xhuDCX+EmlZPaKg+KNEQo4GfMIGcMAkGA1UdEwQCMAAwEAYKKwYB
+BAHWeQIBFgQCBQAwCwYDVR0PBAQDAgXgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0G
+A1UdDgQWBBSBALr9UIk69Md+cjUKU0tkXwICfTAfBgNVHSMEGDAWgBSbJguKmKm7
+HbkfHOMaQDPtjheIqzAbBgNVHREEFDASghB0ZXN0LmV4YW1wbGUub3JnMA0GCSqG
+SIb3DQEBCwUAA4IBAQAe3VMQPQiKtzhjOmcsYvlwZd19Z3xAjv+qOix1aYc+9z2d
+mU/fhTsQVEQt9T2//zqNSboIyz4Qup9PBaBoq3V4hMcKtvLi1YKn64d8FAdPaMsk
++J00zFa+a1ZECuvP9DUnMs86bjebjPv+T9I3dIbok6gnUeHzh/JPt8nYDvB9Uz/L
+NJ5cboS8Zft0oIDR6sQqw9Wk4rCNysFsozT4WjPeqeCopT1rcuRSS/m9QnTGR1SA
+Z4E27vH/Kr/a86bcEve5QXJKqhSb9dW1uORzNwOXVQrFifbF0gx//N5O9v3djydS
+yFe08c9XRSO5RTjukmFWFoLaQV5w8jsuOPjuqc7+
 -----END CERTIFICATE-----
diff --git a/content/test/data/sxg/prime256v1.key b/content/test/data/sxg/prime256v1.key
index 45129fe..bde337a0 100644
--- a/content/test/data/sxg/prime256v1.key
+++ b/content/test/data/sxg/prime256v1.key
@@ -2,7 +2,7 @@
 BggqhkjOPQMBBw==
 -----END EC PARAMETERS-----
 -----BEGIN EC PRIVATE KEY-----
-MHcCAQEEIF0Ta7q/Qu/RmmWZfJI7hcr3f2UAU749HATX0xOGGVPtoAoGCCqGSM49
-AwEHoUQDQgAEw1kBIzFSnMHOGwkgRqAPOAPoqjzjZTZSbNcBCElw10BJc/bXyBnz
-HrOoihuuC7bIMDsEnlgoYh7bNcfjFWCs+w==
+MHcCAQEEIEq/FpadFG7SCIr3Ca9TMHlpZuUr8MqAKoYbI7eRNd9/oAoGCCqGSM49
+AwEHoUQDQgAEViRJegqp3xoKB+OtKiNt6TMlaFqWMwOVEybZRP+oWRZttn1QdG7Z
+951IsmG6+Goe/sYbgwl/hJpWT2ioPijREA==
 -----END EC PRIVATE KEY-----
diff --git a/content/test/data/sxg/secp384r1-sha256.csr b/content/test/data/sxg/secp384r1-sha256.csr
index 2291b4d..6237f70 100644
--- a/content/test/data/sxg/secp384r1-sha256.csr
+++ b/content/test/data/sxg/secp384r1-sha256.csr
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE REQUEST-----
-MIIBLjCBtgIBADA3MRkwFwYDVQQDDBB0ZXN0LmV4YW1wbGUub3JnMQ0wCwYDVQQK
-DARUZXN0MQswCQYDVQQGEwJVUzB2MBAGByqGSM49AgEGBSuBBAAiA2IABF96GJHy
-yeH/ti2z5PLq0xhkX6F1LJdSTdzw1WjMsJDdvpji2lnzETSBJoHyU41nZ/n3qkZp
-nsnyUMZzfw0qbD67P27icsJeHHQGigTJDzSds/nLDFPKQoMkfBVkyO0N6aAAMAoG
-CCqGSM49BAMCA2cAMGQCMAvK+JZU3bs2rVbVJnv+1ukKBxyrlqmBhSk6fWJoVpF5
-WporQviGS6M5os26yz8KqgIwFPguA3Uw468ArZZYbPSacPNLzPysYbGiQGaJS2AN
-rBBHibMS8IhofuhLVkp2K3D5
+MIIBLzCBtgIBADA3MRkwFwYDVQQDDBB0ZXN0LmV4YW1wbGUub3JnMQ0wCwYDVQQK
+DARUZXN0MQswCQYDVQQGEwJVUzB2MBAGByqGSM49AgEGBSuBBAAiA2IABHGex78f
+ymSJY5PstpHt/Qx/YTCNzA/gm5TyZ7iuYEDZ9Q/eJKCAinQm1ZTBW05PYYpbarAZ
+a2tfUP9Vkb5fbC1CNiwwUHWicdAnS9ZkC7YfzBXI2dsDpL/prMiCzxYAVKAAMAoG
+CCqGSM49BAMCA2gAMGUCMEHohXNNEAeTQzDfyqqbDdVJjKAmrNJH91TV3XhUYqVj
+9g8oqf+en9WHQMePAIWoQQIxAJOK7rQ5zaxyjODB52yatItorm7bs0tCUMT/0c8o
+Wykn0PfLgx41EuP3cRw5m2dw3Q==
 -----END CERTIFICATE REQUEST-----
diff --git a/content/test/data/sxg/secp384r1-sha256.public.pem b/content/test/data/sxg/secp384r1-sha256.public.pem
index 149651f9..073643b4 100644
--- a/content/test/data/sxg/secp384r1-sha256.public.pem
+++ b/content/test/data/sxg/secp384r1-sha256.public.pem
@@ -1,7 +1,7 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 4 (0x4)
+        Serial Number: 5 (0x5)
         Signature Algorithm: sha256WithRSAEncryption
         Issuer: C=US, ST=California, L=Mountain View, O=Test CA, CN=Test Root CA
         Validity
@@ -12,13 +12,13 @@
             Public Key Algorithm: id-ecPublicKey
                 Public-Key: (384 bit)
                 pub:
-                    04:5f:7a:18:91:f2:c9:e1:ff:b6:2d:b3:e4:f2:ea:
-                    d3:18:64:5f:a1:75:2c:97:52:4d:dc:f0:d5:68:cc:
-                    b0:90:dd:be:98:e2:da:59:f3:11:34:81:26:81:f2:
-                    53:8d:67:67:f9:f7:aa:46:69:9e:c9:f2:50:c6:73:
-                    7f:0d:2a:6c:3e:bb:3f:6e:e2:72:c2:5e:1c:74:06:
-                    8a:04:c9:0f:34:9d:b3:f9:cb:0c:53:ca:42:83:24:
-                    7c:15:64:c8:ed:0d:e9
+                    04:71:9e:c7:bf:1f:ca:64:89:63:93:ec:b6:91:ed:
+                    fd:0c:7f:61:30:8d:cc:0f:e0:9b:94:f2:67:b8:ae:
+                    60:40:d9:f5:0f:de:24:a0:80:8a:74:26:d5:94:c1:
+                    5b:4e:4f:61:8a:5b:6a:b0:19:6b:6b:5f:50:ff:55:
+                    91:be:5f:6c:2d:42:36:2c:30:50:75:a2:71:d0:27:
+                    4b:d6:64:0b:b6:1f:cc:15:c8:d9:db:03:a4:bf:e9:
+                    ac:c8:82:cf:16:00:54
                 ASN1 OID: secp384r1
                 NIST CURVE: P-384
         X509v3 extensions:
@@ -28,44 +28,47 @@
                 ..
             X509v3 Key Usage: 
                 Digital Signature, Non Repudiation, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication
             X509v3 Subject Key Identifier: 
-                8C:9E:71:9F:22:BD:E5:7B:91:7B:BE:A0:91:4C:DB:8A:B2:A9:D3:B1
+                93:76:D0:33:7C:F7:12:E0:D0:D8:1F:31:65:C0:97:8A:1D:34:77:1B
             X509v3 Authority Key Identifier: 
                 keyid:9B:26:0B:8A:98:A9:BB:1D:B9:1F:1C:E3:1A:40:33:ED:8E:17:88:AB
 
             X509v3 Subject Alternative Name: 
                 DNS:test.example.org
     Signature Algorithm: sha256WithRSAEncryption
-         30:4e:53:7d:dd:a6:00:16:c8:86:57:e3:79:1c:ef:54:7c:11:
-         99:b5:ad:1f:15:74:4d:e9:d5:c9:e4:3b:59:f3:e0:3f:77:5a:
-         22:e4:4d:4d:cd:e4:ab:08:bf:32:f9:71:90:aa:75:d8:6d:79:
-         f1:10:8e:02:08:5f:b8:0e:e4:1e:4c:2f:93:ec:2e:d1:e5:e7:
-         fc:c7:31:b3:1f:4f:e3:d7:26:3e:ad:f4:51:d6:3e:a4:7d:b1:
-         90:5b:be:b6:da:b0:f5:b2:9c:88:ee:20:a2:fe:c2:cc:a6:02:
-         8b:16:d5:93:d2:3e:71:4e:68:ef:c8:20:6c:5c:8b:ca:93:33:
-         5c:46:6b:b6:83:48:ac:5e:eb:24:fe:b6:8e:a5:d2:5a:0d:b8:
-         90:66:a5:e9:51:77:ef:b8:3f:c2:fa:43:67:72:38:71:cd:6a:
-         60:c6:d8:99:e5:af:b4:44:82:b3:3e:77:b6:1f:56:31:ad:65:
-         d6:08:0b:c9:48:29:4a:56:dc:ad:1b:e2:65:8c:3b:40:40:ca:
-         53:df:96:3a:20:1d:f2:9a:34:48:34:89:cf:85:f7:d4:19:58:
-         b8:e1:dc:65:fb:ad:3b:d9:79:c0:9b:ea:a8:08:88:e6:83:e2:
-         6c:dd:4e:5c:00:98:35:e9:b6:1d:d2:b4:91:6e:5a:90:92:42:
-         6f:87:8b:5b
+         0c:6b:0c:18:98:13:4e:39:ad:0c:19:d7:62:f0:06:20:5f:75:
+         5d:bd:43:f0:1a:ce:2e:fc:90:90:8f:3f:42:52:03:b9:82:ea:
+         a7:5f:cc:cf:c8:a4:69:35:55:8f:8f:d1:b7:22:d6:ee:78:91:
+         5d:7a:af:d7:80:55:26:f1:1d:f5:1d:c6:d1:64:f4:19:95:0c:
+         bd:44:cd:bd:57:68:4e:a3:b9:ce:18:a7:5f:f8:e0:0f:a1:42:
+         71:cb:b9:0e:7f:38:24:01:3c:03:45:f1:92:e1:cf:d5:ce:65:
+         b6:94:e0:b2:f3:b6:26:bf:3d:cc:0a:3a:45:a3:af:fe:c9:5b:
+         f5:b9:46:b9:32:87:16:5d:01:30:98:03:ea:d3:c4:3f:14:d8:
+         0d:cf:e5:0a:3b:11:29:6e:3f:ad:b6:d1:cc:da:c7:14:46:21:
+         1d:6a:dd:b8:3e:c4:df:fb:35:f9:63:7f:8e:51:92:5f:01:38:
+         d2:fc:7f:d1:70:be:bd:69:7c:5c:75:56:1e:0c:43:35:af:04:
+         ed:1b:d1:73:67:32:e3:63:c7:a5:65:a8:97:d2:4b:5e:1e:23:
+         2c:12:f9:f9:ab:1f:03:0f:b5:4d:c1:c7:52:38:5a:40:34:ec:
+         30:9c:6d:45:21:fa:06:7e:6d:8b:93:51:f0:36:d9:02:f6:87:
+         12:03:06:2c
 -----BEGIN CERTIFICATE-----
-MIIC8jCCAdqgAwIBAgIBBDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzET
+MIIDBzCCAe+gAwIBAgIBBTANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzET
 MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G
 A1UECgwHVGVzdCBDQTEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTE5MDYwMTAw
 MDAwMFoXDTE5MDgzMDAwMDAwMFowNzEZMBcGA1UEAwwQdGVzdC5leGFtcGxlLm9y
 ZzENMAsGA1UECgwEVGVzdDELMAkGA1UEBhMCVVMwdjAQBgcqhkjOPQIBBgUrgQQA
-IgNiAARfehiR8snh/7Yts+Ty6tMYZF+hdSyXUk3c8NVozLCQ3b6Y4tpZ8xE0gSaB
-8lONZ2f596pGaZ7J8lDGc38NKmw+uz9u4nLCXhx0BooEyQ80nbP5ywxTykKDJHwV
-ZMjtDemjgYowgYcwCQYDVR0TBAIwADAQBgorBgEEAdZ5AgEWBAIFADALBgNVHQ8E
-BAMCBeAwHQYDVR0OBBYEFIyecZ8iveV7kXu+oJFM24qyqdOxMB8GA1UdIwQYMBaA
-FJsmC4qYqbsduR8c4xpAM+2OF4irMBsGA1UdEQQUMBKCEHRlc3QuZXhhbXBsZS5v
-cmcwDQYJKoZIhvcNAQELBQADggEBADBOU33dpgAWyIZX43kc71R8EZm1rR8VdE3p
-1cnkO1nz4D93WiLkTU3N5KsIvzL5cZCqddhtefEQjgIIX7gO5B5ML5PsLtHl5/zH
-MbMfT+PXJj6t9FHWPqR9sZBbvrbasPWynIjuIKL+wsymAosW1ZPSPnFOaO/IIGxc
-i8qTM1xGa7aDSKxe6yT+to6l0loNuJBmpelRd++4P8L6Q2dyOHHNamDG2Jnlr7RE
-grM+d7YfVjGtZdYIC8lIKUpW3K0b4mWMO0BAylPfljogHfKaNEg0ic+F99QZWLjh
-3GX7rTvZecCb6qgIiOaD4mzdTlwAmDXpth3StJFuWpCSQm+Hi1s=
+IgNiAARxnse/H8pkiWOT7LaR7f0Mf2EwjcwP4JuU8me4rmBA2fUP3iSggIp0JtWU
+wVtOT2GKW2qwGWtrX1D/VZG+X2wtQjYsMFB1onHQJ0vWZAu2H8wVyNnbA6S/6azI
+gs8WAFSjgZ8wgZwwCQYDVR0TBAIwADAQBgorBgEEAdZ5AgEWBAIFADALBgNVHQ8E
+BAMCBeAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFJN20DN89xLg0Ngf
+MWXAl4odNHcbMB8GA1UdIwQYMBaAFJsmC4qYqbsduR8c4xpAM+2OF4irMBsGA1Ud
+EQQUMBKCEHRlc3QuZXhhbXBsZS5vcmcwDQYJKoZIhvcNAQELBQADggEBAAxrDBiY
+E045rQwZ12LwBiBfdV29Q/Aazi78kJCPP0JSA7mC6qdfzM/IpGk1VY+P0bci1u54
+kV16r9eAVSbxHfUdxtFk9BmVDL1Ezb1XaE6juc4Yp1/44A+hQnHLuQ5/OCQBPANF
+8ZLhz9XOZbaU4LLztia/PcwKOkWjr/7JW/W5RrkyhxZdATCYA+rTxD8U2A3P5Qo7
+ESluP6220czaxxRGIR1q3bg+xN/7Nfljf45Rkl8BONL8f9Fwvr1pfFx1Vh4MQzWv
+BO0b0XNnMuNjx6VlqJfSS14eIywS+fmrHwMPtU3Bx1I4WkA07DCcbUUh+gZ+bYuT
+UfA22QL2hxIDBiw=
 -----END CERTIFICATE-----
diff --git a/content/test/data/sxg/secp384r1.key b/content/test/data/sxg/secp384r1.key
index 42a7f0c..c2cde1d2 100644
--- a/content/test/data/sxg/secp384r1.key
+++ b/content/test/data/sxg/secp384r1.key
@@ -2,8 +2,8 @@
 BgUrgQQAIg==
 -----END EC PARAMETERS-----
 -----BEGIN EC PRIVATE KEY-----
-MIGkAgEBBDCms5TUSm7gkgyaWroajqN4vnbRcRj+6wxzalF9s23dx2Uek4boMmd9
-AXRl8q9PkDagBwYFK4EEACKhZANiAARfehiR8snh/7Yts+Ty6tMYZF+hdSyXUk3c
-8NVozLCQ3b6Y4tpZ8xE0gSaB8lONZ2f596pGaZ7J8lDGc38NKmw+uz9u4nLCXhx0
-BooEyQ80nbP5ywxTykKDJHwVZMjtDek=
+MIGkAgEBBDCpLgEyXpuUhNnL70pb0AtsB7k+LT6oD36Q/2Mrj7ukipmdhnq5LA7b
+S1NInwaft6ygBwYFK4EEACKhZANiAARxnse/H8pkiWOT7LaR7f0Mf2EwjcwP4JuU
+8me4rmBA2fUP3iSggIp0JtWUwVtOT2GKW2qwGWtrX1D/VZG+X2wtQjYsMFB1onHQ
+J0vWZAu2H8wVyNnbA6S/6azIgs8WAFQ=
 -----END EC PRIVATE KEY-----
diff --git a/content/test/data/sxg/test.example.com_invalid_test.sxg b/content/test/data/sxg/test.example.com_invalid_test.sxg
index 8dac6eab..f35afc9 100644
--- a/content/test/data/sxg/test.example.com_invalid_test.sxg
+++ b/content/test/data/sxg/test.example.com_invalid_test.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org-long-validity.public.pem.cbor b/content/test/data/sxg/test.example.org-long-validity.public.pem.cbor
index a9173dc..4bbc2743 100644
--- a/content/test/data/sxg/test.example.org-long-validity.public.pem.cbor
+++ b/content/test/data/sxg/test.example.org-long-validity.public.pem.cbor
Binary files differ
diff --git a/content/test/data/sxg/test.example.org-noext.public.pem.cbor b/content/test/data/sxg/test.example.org-noext.public.pem.cbor
index 52c7933..ca11624 100644
--- a/content/test/data/sxg/test.example.org-noext.public.pem.cbor
+++ b/content/test/data/sxg/test.example.org-noext.public.pem.cbor
Binary files differ
diff --git a/content/test/data/sxg/test.example.org-validity-too-long.public.pem.cbor b/content/test/data/sxg/test.example.org-validity-too-long.public.pem.cbor
index 058c1d36..4fa4b40 100644
--- a/content/test/data/sxg/test.example.org-validity-too-long.public.pem.cbor
+++ b/content/test/data/sxg/test.example.org-validity-too-long.public.pem.cbor
Binary files differ
diff --git a/content/test/data/sxg/test.example.org.public.pem.cbor b/content/test/data/sxg/test.example.org.public.pem.cbor
index 1be7dfac..4a647a182 100644
--- a/content/test/data/sxg/test.example.org.public.pem.cbor
+++ b/content/test/data/sxg/test.example.org.public.pem.cbor
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_cert_validity_too_long.sxg b/content/test/data/sxg/test.example.org_cert_validity_too_long.sxg
index c4a746d..d0e38bb 100644
--- a/content/test/data/sxg/test.example.org_cert_validity_too_long.sxg
+++ b/content/test/data/sxg/test.example.org_cert_validity_too_long.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_fr_variant.sxg b/content/test/data/sxg/test.example.org_fr_variant.sxg
index 4c62d6e..3160130c 100644
--- a/content/test/data/sxg/test.example.org_fr_variant.sxg
+++ b/content/test/data/sxg/test.example.org_fr_variant.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_hello.txt.sxg b/content/test/data/sxg/test.example.org_hello.txt.sxg
index f4d54f3..5585239 100644
--- a/content/test/data/sxg/test.example.org_hello.txt.sxg
+++ b/content/test/data/sxg/test.example.org_hello.txt.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_long_cert_validity.sxg b/content/test/data/sxg/test.example.org_long_cert_validity.sxg
index d22900d..257f402d 100644
--- a/content/test/data/sxg/test.example.org_long_cert_validity.sxg
+++ b/content/test/data/sxg/test.example.org_long_cert_validity.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_noext_test.sxg b/content/test/data/sxg/test.example.org_noext_test.sxg
index ae7d03ae..d29b3fd 100644
--- a/content/test/data/sxg/test.example.org_noext_test.sxg
+++ b/content/test/data/sxg/test.example.org_noext_test.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_test.html.gz.sxg b/content/test/data/sxg/test.example.org_test.html.gz.sxg
index d764a133..1560f89 100644
--- a/content/test/data/sxg/test.example.org_test.html.gz.sxg
+++ b/content/test/data/sxg/test.example.org_test.html.gz.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_test.sxg b/content/test/data/sxg/test.example.org_test.sxg
index 64b0b1d..f048767 100644
--- a/content/test/data/sxg/test.example.org_test.sxg
+++ b/content/test/data/sxg/test.example.org_test.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_test_bad_mice.sxg b/content/test/data/sxg/test.example.org_test_bad_mice.sxg
index b6a71ef..4118339 100644
--- a/content/test/data/sxg/test.example.org_test_bad_mice.sxg
+++ b/content/test/data/sxg/test.example.org_test_bad_mice.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_test_bad_mice_small.sxg b/content/test/data/sxg/test.example.org_test_bad_mice_small.sxg
index de21a5d..d01220e 100644
--- a/content/test/data/sxg/test.example.org_test_bad_mice_small.sxg
+++ b/content/test/data/sxg/test.example.org_test_bad_mice_small.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_test_download.sxg b/content/test/data/sxg/test.example.org_test_download.sxg
index 64b0b1d..f048767 100644
--- a/content/test/data/sxg/test.example.org_test_download.sxg
+++ b/content/test/data/sxg/test.example.org_test_download.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_test_invalid_cbor_header.sxg b/content/test/data/sxg/test.example.org_test_invalid_cbor_header.sxg
index 9e614af..99a3448 100644
--- a/content/test/data/sxg/test.example.org_test_invalid_cbor_header.sxg
+++ b/content/test/data/sxg/test.example.org_test_invalid_cbor_header.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_test_invalid_content_type.sxg b/content/test/data/sxg/test.example.org_test_invalid_content_type.sxg
index 64b0b1d..f048767 100644
--- a/content/test/data/sxg/test.example.org_test_invalid_content_type.sxg
+++ b/content/test/data/sxg/test.example.org_test_invalid_content_type.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_test_invalid_magic_string.sxg b/content/test/data/sxg/test.example.org_test_invalid_magic_string.sxg
index 4a29df6..e9515088 100644
--- a/content/test/data/sxg/test.example.org_test_invalid_magic_string.sxg
+++ b/content/test/data/sxg/test.example.org_test_invalid_magic_string.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_test_missing_nosniff.sxg b/content/test/data/sxg/test.example.org_test_missing_nosniff.sxg
index 64b0b1d..f048767 100644
--- a/content/test/data/sxg/test.example.org_test_missing_nosniff.sxg
+++ b/content/test/data/sxg/test.example.org_test_missing_nosniff.sxg
Binary files differ
diff --git a/content/test/fake_compositor_dependencies.cc b/content/test/fake_compositor_dependencies.cc
index 5c2770ca..9791847 100644
--- a/content/test/fake_compositor_dependencies.cc
+++ b/content/test/fake_compositor_dependencies.cc
@@ -89,7 +89,8 @@
     LayerTreeFrameSinkCallback callback,
     mojom::RenderFrameMetadataObserverClientRequest
         render_frame_metadata_observer_client_request,
-    mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer_ptr,
+    mojo::PendingRemote<mojom::RenderFrameMetadataObserver>
+        render_frame_metadata_observer_remote,
     const char* client_name) {
   std::move(callback).Run(cc::FakeLayerTreeFrameSink::Create3d());
 }
diff --git a/content/test/fake_compositor_dependencies.h b/content/test/fake_compositor_dependencies.h
index a4a4e157..2305748e 100644
--- a/content/test/fake_compositor_dependencies.h
+++ b/content/test/fake_compositor_dependencies.h
@@ -9,6 +9,7 @@
 #include "base/single_thread_task_runner.h"
 #include "cc/test/test_task_graph_runner.h"
 #include "content/renderer/compositor/compositor_dependencies.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/platform/scheduler/test/web_fake_thread_scheduler.h"
 
 namespace content {
@@ -42,7 +43,8 @@
       LayerTreeFrameSinkCallback callback,
       mojom::RenderFrameMetadataObserverClientRequest
           render_frame_metadata_observer_client_request,
-      mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer_ptr,
+      mojo::PendingRemote<mojom::RenderFrameMetadataObserver>
+          render_frame_metadata_observer_remote,
       const char* client_name) override;
 #ifdef OS_ANDROID
   bool UsingSynchronousCompositing() override;
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index aab4e3a7..5f73e0e 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -194,7 +194,6 @@
 crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_OffscreenCanvasWebGLSoftwareCompositingWorker [ Skip ]
 crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_RepeatedWebGLTo2D_SoftwareCompositing [ Skip ]
 crbug.com/985366 [ linux skia-renderer use-vulkan ] Pixel_CanvasLowLatency2D [ Skip ]
-crbug.com/985366 [ linux skia-renderer use-vulkan ] Pixel_CanvasLowLatencyWebGL [ Skip ]
 
 # Also producing blank images on Intel
 crbug.com/974383 [ linux skia-renderer use-vulkan intel ] Pixel_CanvasDisplayLinearRGBAccelerated2D [ Skip ]
diff --git a/extensions/browser/api/serial/serial_api.cc b/extensions/browser/api/serial/serial_api.cc
index 1526c33..910e3fc 100644
--- a/extensions/browser/api/serial/serial_api.cc
+++ b/extensions/browser/api/serial/serial_api.cc
@@ -13,15 +13,13 @@
 #include "base/task/post_task.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "content/public/browser/browser_thread.h"
+#include "extensions/browser/api/api_resource_manager.h"
 #include "extensions/browser/api/serial/serial_connection.h"
 #include "extensions/browser/api/serial/serial_port_manager.h"
 #include "extensions/common/api/serial.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 
-using content::BrowserThread;
-
 namespace extensions {
 
 namespace api {
@@ -55,35 +53,24 @@
 
 }  // namespace
 
-SerialAsyncApiFunction::SerialAsyncApiFunction() : manager_(nullptr) {}
+SerialExtensionFunction::SerialExtensionFunction() = default;
+SerialExtensionFunction::~SerialExtensionFunction() = default;
 
-SerialAsyncApiFunction::~SerialAsyncApiFunction() {}
-
-bool SerialAsyncApiFunction::PrePrepare() {
-  manager_ = ApiResourceManager<SerialConnection>::Get(browser_context());
-  DCHECK(manager_);
-  return true;
-}
-
-bool SerialAsyncApiFunction::Respond() {
-  return error_.empty();
-}
-
-SerialConnection* SerialAsyncApiFunction::GetSerialConnection(
+SerialConnection* SerialExtensionFunction::GetSerialConnection(
     int api_resource_id) {
-  return manager_->Get(extension_->id(), api_resource_id);
+  auto* manager = ApiResourceManager<SerialConnection>::Get(browser_context());
+  return manager->Get(extension_->id(), api_resource_id);
 }
 
-void SerialAsyncApiFunction::RemoveSerialConnection(int api_resource_id) {
-  manager_->Remove(extension_->id(), api_resource_id);
+void SerialExtensionFunction::RemoveSerialConnection(int api_resource_id) {
+  auto* manager = ApiResourceManager<SerialConnection>::Get(browser_context());
+  manager->Remove(extension_->id(), api_resource_id);
 }
 
-SerialGetDevicesFunction::SerialGetDevicesFunction() {}
-
-SerialGetDevicesFunction::~SerialGetDevicesFunction() {}
+SerialGetDevicesFunction::SerialGetDevicesFunction() = default;
+SerialGetDevicesFunction::~SerialGetDevicesFunction() = default;
 
 ExtensionFunction::ResponseAction SerialGetDevicesFunction::Run() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   auto* port_manager = SerialPortManager::Get(browser_context());
   DCHECK(port_manager);
   port_manager->GetDevices(mojo::WrapCallbackWithDefaultInvokeIfNotRun(
@@ -94,24 +81,22 @@
 
 void SerialGetDevicesFunction::OnGotDevices(
     std::vector<device::mojom::SerialPortInfoPtr> devices) {
-  std::unique_ptr<base::ListValue> results =
-      serial::GetDevices::Results::Create(
-          mojo::ConvertTo<std::vector<serial::DeviceInfo>>(devices));
-  Respond(ArgumentList(std::move(results)));
+  Respond(ArgumentList(serial::GetDevices::Results::Create(
+      mojo::ConvertTo<std::vector<serial::DeviceInfo>>(devices))));
 }
 
 SerialConnectFunction::SerialConnectFunction() {}
 
 SerialConnectFunction::~SerialConnectFunction() {}
 
-bool SerialConnectFunction::Prepare() {
-  params_ = serial::Connect::Params::Create(*args_);
-  EXTENSION_FUNCTION_VALIDATE(params_.get());
+ExtensionFunction::ResponseAction SerialConnectFunction::Run() {
+  auto params = serial::Connect::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
   // Fill in any omitted options to ensure a known initial configuration.
-  if (!params_->options.get())
-    params_->options.reset(new serial::ConnectionOptions());
-  serial::ConnectionOptions* options = params_->options.get();
+  if (!params->options)
+    params->options = std::make_unique<serial::ConnectionOptions>();
+  serial::ConnectionOptions* options = params->options.get();
 
   SetDefaultScopedPtrValue(options->persistent, false);
   SetDefaultScopedPtrValue(options->buffer_size, kDefaultBufferSize);
@@ -127,25 +112,20 @@
   if (options->stop_bits == serial::STOP_BITS_NONE)
     options->stop_bits = kDefaultStopBits;
 
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  serial_port_manager_ = SerialPortManager::Get(browser_context());
-  DCHECK(serial_port_manager_);
-  serial_port_manager_->GetPort(params_->path,
-                                mojo::MakeRequest(&serial_port_info_));
+  auto* manager = SerialPortManager::Get(browser_context());
+  DCHECK(manager);
 
-  return true;
-}
+  device::mojom::SerialPortPtr serial_port;
+  manager->GetPort(params->path, mojo::MakeRequest(&serial_port));
 
-void SerialConnectFunction::AsyncWorkStart() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  connection_ = std::make_unique<SerialConnection>(
-      extension_->id(), std::move(serial_port_info_));
-  connection_->Open(*params_->options,
+  connection_ = std::make_unique<SerialConnection>(extension_->id(),
+                                                   std::move(serial_port));
+  connection_->Open(*params->options,
                     base::BindOnce(&SerialConnectFunction::OnConnected, this));
+  return RespondLater();
 }
 
 void SerialConnectFunction::OnConnected(bool success) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(connection_);
 
   if (!success) {
@@ -161,114 +141,95 @@
     bool connected,
     bool got_complete_info,
     std::unique_ptr<serial::ConnectionInfo> info) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(connection_);
   if (!connected || !got_complete_info) {
-    error_ = kErrorConnectFailed;
+    Respond(Error(kErrorConnectFailed));
     connection_.reset();
   } else {
     DCHECK(info);
-    int id = manager_->Add(connection_.release());
+    auto* manager =
+        ApiResourceManager<SerialConnection>::Get(browser_context());
+    int id = manager->Add(connection_.release());
     // If a SerialConnection encountered a mojo connection error, it just
     // becomes useless, we won't try to re-connect it but just remove it
     // completely.
-    GetSerialConnection(id)->SetConnectionErrorHandler(base::BindOnce(
+    SerialConnection* connection = GetSerialConnection(id);
+    connection->SetConnectionErrorHandler(base::BindOnce(
         [](scoped_refptr<ApiResourceManager<SerialConnection>::ApiResourceData>
                connections,
            std::string extension_id, int api_resource_id) {
           connections->Remove(extension_id, api_resource_id);
         },
-        manager_->data_, extension_->id(), id));
+        manager->data_, extension_->id(), id));
     info->connection_id = id;
     // Start polling.
-    serial_port_manager_->StartConnectionPolling(extension_->id(), id);
-    results_ = serial::Connect::Results::Create(*info);
+    auto* port_manager = SerialPortManager::Get(browser_context());
+    port_manager->StartConnectionPolling(extension_->id(), id);
+    Respond(OneArgument(info->ToValue()));
   }
-  AsyncWorkCompleted();
 }
 
-SerialUpdateFunction::SerialUpdateFunction() {}
+SerialUpdateFunction::SerialUpdateFunction() = default;
+SerialUpdateFunction::~SerialUpdateFunction() = default;
 
-SerialUpdateFunction::~SerialUpdateFunction() {}
+ExtensionFunction::ResponseAction SerialUpdateFunction::Run() {
+  auto params = serial::Update::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
-bool SerialUpdateFunction::Prepare() {
-  params_ = serial::Update::Params::Create(*args_);
-  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  SerialConnection* connection = GetSerialConnection(params->connection_id);
+  if (!connection)
+    return RespondNow(Error(kErrorSerialConnectionNotFound));
 
-  return true;
-}
-
-void SerialUpdateFunction::AsyncWorkStart() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  SerialConnection* connection = GetSerialConnection(params_->connection_id);
-  if (!connection) {
-    error_ = kErrorSerialConnectionNotFound;
-    AsyncWorkCompleted();
-    return;
-  }
-  connection->Configure(params_->options,
+  connection->Configure(params->options,
                         base::BindOnce(&SerialUpdateFunction::OnUpdated, this));
+  return RespondLater();
 }
 
 void SerialUpdateFunction::OnUpdated(bool success) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  results_ = serial::Update::Results::Create(success);
-  AsyncWorkCompleted();
+  Respond(OneArgument(std::make_unique<base::Value>(success)));
 }
 
-SerialDisconnectFunction::SerialDisconnectFunction() {}
+SerialDisconnectFunction::SerialDisconnectFunction() = default;
+SerialDisconnectFunction::~SerialDisconnectFunction() = default;
 
-SerialDisconnectFunction::~SerialDisconnectFunction() {}
+ExtensionFunction::ResponseAction SerialDisconnectFunction::Run() {
+  auto params = serial::Disconnect::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
-bool SerialDisconnectFunction::Prepare() {
-  params_ = serial::Disconnect::Params::Create(*args_);
-  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  SerialConnection* connection = GetSerialConnection(params->connection_id);
+  if (!connection)
+    return RespondNow(Error(kErrorSerialConnectionNotFound));
 
-  return true;
+  connection->Close(base::BindOnce(&SerialDisconnectFunction::OnCloseComplete,
+                                   this, params->connection_id));
+  return RespondLater();
 }
 
-void SerialDisconnectFunction::AsyncWorkStart() {
-  SerialConnection* connection = GetSerialConnection(params_->connection_id);
-  if (!connection) {
-    error_ = kErrorSerialConnectionNotFound;
-    AsyncWorkCompleted();
-    return;
-  }
-
-  connection->Close(
-      base::BindOnce(&SerialDisconnectFunction::OnCloseComplete, this));
+void SerialDisconnectFunction::OnCloseComplete(int connection_id) {
+  RemoveSerialConnection(connection_id);
+  Respond(OneArgument(std::make_unique<base::Value>(true)));
 }
 
-void SerialDisconnectFunction::OnCloseComplete() {
-  results_ = serial::Disconnect::Results::Create(true);
-  RemoveSerialConnection(params_->connection_id);
-  AsyncWorkCompleted();
-}
+SerialSendFunction::SerialSendFunction() = default;
+SerialSendFunction::~SerialSendFunction() = default;
 
-SerialSendFunction::SerialSendFunction() {}
+ExtensionFunction::ResponseAction SerialSendFunction::Run() {
+  auto params = serial::Send::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
-SerialSendFunction::~SerialSendFunction() {}
-
-bool SerialSendFunction::Prepare() {
-  params_ = serial::Send::Params::Create(*args_);
-  EXTENSION_FUNCTION_VALIDATE(params_.get());
-
-  return true;
-}
-
-void SerialSendFunction::AsyncWorkStart() {
-  SerialConnection* connection = GetSerialConnection(params_->connection_id);
-  if (!connection) {
-    error_ = kErrorSerialConnectionNotFound;
-    AsyncWorkCompleted();
-    return;
-  }
+  SerialConnection* connection = GetSerialConnection(params->connection_id);
+  if (!connection)
+    return RespondNow(Error(kErrorSerialConnectionNotFound));
 
   if (!connection->Send(
-          params_->data,
+          params->data,
           base::BindOnce(&SerialSendFunction::OnSendComplete, this))) {
-    OnSendComplete(0, serial::SEND_ERROR_PENDING);
+    serial::SendInfo send_info;
+    send_info.bytes_sent = 0;
+    send_info.error = serial::SEND_ERROR_PENDING;
+    return RespondNow(OneArgument(send_info.ToValue()));
   }
+  return RespondLater();
 }
 
 void SerialSendFunction::OnSendComplete(uint32_t bytes_sent,
@@ -276,109 +237,77 @@
   serial::SendInfo send_info;
   send_info.bytes_sent = bytes_sent;
   send_info.error = error;
-  results_ = serial::Send::Results::Create(send_info);
-  AsyncWorkCompleted();
+  Respond(OneArgument(send_info.ToValue()));
 }
 
-SerialFlushFunction::SerialFlushFunction() {}
+SerialFlushFunction::SerialFlushFunction() = default;
+SerialFlushFunction::~SerialFlushFunction() = default;
 
-SerialFlushFunction::~SerialFlushFunction() {}
+ExtensionFunction::ResponseAction SerialFlushFunction::Run() {
+  auto params = serial::Flush::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
-bool SerialFlushFunction::Prepare() {
-  params_ = serial::Flush::Params::Create(*args_);
-  EXTENSION_FUNCTION_VALIDATE(params_.get());
-  return true;
-}
+  SerialConnection* connection = GetSerialConnection(params->connection_id);
+  if (!connection)
+    return RespondNow(Error(kErrorSerialConnectionNotFound));
 
-void SerialFlushFunction::AsyncWorkStart() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  SerialConnection* connection = GetSerialConnection(params_->connection_id);
-  if (!connection) {
-    error_ = kErrorSerialConnectionNotFound;
-    AsyncWorkCompleted();
-    return;
-  }
   connection->Flush(base::BindOnce(&SerialFlushFunction::OnFlushed, this));
+  return RespondLater();
 }
 
 void SerialFlushFunction::OnFlushed(bool success) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  results_ = serial::Flush::Results::Create(success);
-  AsyncWorkCompleted();
+  Respond(OneArgument(std::make_unique<base::Value>(success)));
 }
 
-SerialSetPausedFunction::SerialSetPausedFunction() {}
+SerialSetPausedFunction::SerialSetPausedFunction() = default;
+SerialSetPausedFunction::~SerialSetPausedFunction() = default;
 
-SerialSetPausedFunction::~SerialSetPausedFunction() {}
+ExtensionFunction::ResponseAction SerialSetPausedFunction::Run() {
+  auto params = serial::SetPaused::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
-bool SerialSetPausedFunction::Prepare() {
-  params_ = serial::SetPaused::Params::Create(*args_);
-  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  SerialConnection* connection = GetSerialConnection(params->connection_id);
+  if (!connection)
+    return RespondNow(Error(kErrorSerialConnectionNotFound));
 
-  serial_port_manager_ = SerialPortManager::Get(browser_context());
-  DCHECK(serial_port_manager_);
-  return true;
+  if (params->paused != connection->paused())
+    connection->SetPaused(params->paused);
+
+  return RespondNow(NoArguments());
 }
 
-void SerialSetPausedFunction::Work() {
-  SerialConnection* connection = GetSerialConnection(params_->connection_id);
-  if (!connection) {
-    error_ = kErrorSerialConnectionNotFound;
-    return;
-  }
+SerialGetInfoFunction::SerialGetInfoFunction() = default;
+SerialGetInfoFunction::~SerialGetInfoFunction() = default;
 
-  if (params_->paused != connection->paused()) {
-    connection->SetPaused(params_->paused);
-  }
+ExtensionFunction::ResponseAction SerialGetInfoFunction::Run() {
+  auto params = serial::GetInfo::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  results_ = serial::SetPaused::Results::Create();
-}
+  SerialConnection* connection = GetSerialConnection(params->connection_id);
+  if (!connection)
+    return RespondNow(Error(kErrorSerialConnectionNotFound));
 
-SerialGetInfoFunction::SerialGetInfoFunction() {}
-
-SerialGetInfoFunction::~SerialGetInfoFunction() {}
-
-bool SerialGetInfoFunction::Prepare() {
-  params_ = serial::GetInfo::Params::Create(*args_);
-  EXTENSION_FUNCTION_VALIDATE(params_.get());
-
-  return true;
-}
-
-void SerialGetInfoFunction::AsyncWorkStart() {
-  SerialConnection* connection = GetSerialConnection(params_->connection_id);
-  if (!connection) {
-    error_ = kErrorSerialConnectionNotFound;
-    AsyncWorkCompleted();
-    return;
-  }
-
-  connection->GetInfo(base::BindOnce(&SerialGetInfoFunction::OnGotInfo, this));
+  connection->GetInfo(base::BindOnce(&SerialGetInfoFunction::OnGotInfo, this,
+                                     params->connection_id));
+  return RespondLater();
 }
 
 void SerialGetInfoFunction::OnGotInfo(
+    int connection_id,
     bool got_complete_info,
     std::unique_ptr<serial::ConnectionInfo> info) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(info);
-  info->connection_id = params_->connection_id;
-  results_ = serial::GetInfo::Results::Create(*info);
-
-  AsyncWorkCompleted();
+  info->connection_id = connection_id;
+  Respond(OneArgument(info->ToValue()));
 }
 
-SerialGetConnectionsFunction::SerialGetConnectionsFunction() {}
+SerialGetConnectionsFunction::SerialGetConnectionsFunction() = default;
+SerialGetConnectionsFunction::~SerialGetConnectionsFunction() = default;
 
-SerialGetConnectionsFunction::~SerialGetConnectionsFunction() {}
-
-bool SerialGetConnectionsFunction::Prepare() {
-  return true;
-}
-
-void SerialGetConnectionsFunction::AsyncWorkStart() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ExtensionFunction::ResponseAction SerialGetConnectionsFunction::Run() {
+  auto* manager = ApiResourceManager<SerialConnection>::Get(browser_context());
   const std::unordered_set<int>* connection_ids =
-      manager_->GetResourceIds(extension_->id());
+      manager->GetResourceIds(extension_->id());
   if (connection_ids) {
     for (auto it = connection_ids->cbegin(); it != connection_ids->cend();
          ++it) {
@@ -391,163 +320,119 @@
       }
     }
   }
-  if (count_ > 0)
-    return;
 
-  OnGotAll();
+  if (count_ > 0)
+    return RespondLater();
+
+  return RespondNow(ArgumentList(serial::GetConnections::Results::Create(
+      std::vector<serial::ConnectionInfo>())));
 }
 
 void SerialGetConnectionsFunction::OnGotOne(
     int connection_id,
     bool got_complete_info,
     std::unique_ptr<serial::ConnectionInfo> info) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(info);
   info->connection_id = connection_id;
   infos_.push_back(std::move(*info));
 
-  if (infos_.size() == count_) {
-    OnGotAll();
-  }
+  if (infos_.size() == count_)
+    Respond(ArgumentList(serial::GetConnections::Results::Create(infos_)));
 }
 
-void SerialGetConnectionsFunction::OnGotAll() {
-  results_ = serial::GetConnections::Results::Create(infos_);
-  AsyncWorkCompleted();
-}
+SerialGetControlSignalsFunction::SerialGetControlSignalsFunction() = default;
+SerialGetControlSignalsFunction::~SerialGetControlSignalsFunction() = default;
 
-SerialGetControlSignalsFunction::SerialGetControlSignalsFunction() {}
+ExtensionFunction::ResponseAction SerialGetControlSignalsFunction::Run() {
+  auto params = serial::GetControlSignals::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
-SerialGetControlSignalsFunction::~SerialGetControlSignalsFunction() {}
-
-bool SerialGetControlSignalsFunction::Prepare() {
-  params_ = serial::GetControlSignals::Params::Create(*args_);
-  EXTENSION_FUNCTION_VALIDATE(params_.get());
-
-  return true;
-}
-
-void SerialGetControlSignalsFunction::AsyncWorkStart() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  SerialConnection* connection = GetSerialConnection(params_->connection_id);
-  if (!connection) {
-    error_ = kErrorSerialConnectionNotFound;
-    AsyncWorkCompleted();
-    return;
-  }
+  SerialConnection* connection = GetSerialConnection(params->connection_id);
+  if (!connection)
+    return RespondNow(Error(kErrorSerialConnectionNotFound));
 
   connection->GetControlSignals(base::BindOnce(
       &SerialGetControlSignalsFunction::OnGotControlSignals, this));
+  return RespondLater();
 }
 
 void SerialGetControlSignalsFunction::OnGotControlSignals(
     std::unique_ptr<serial::DeviceControlSignals> signals) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (!signals) {
-    error_ = kErrorGetControlSignalsFailed;
+    Respond(Error(kErrorGetControlSignalsFailed));
   } else {
-    results_ = serial::GetControlSignals::Results::Create(*signals);
+    Respond(OneArgument(signals->ToValue()));
   }
-
-  AsyncWorkCompleted();
 }
 
-SerialSetControlSignalsFunction::SerialSetControlSignalsFunction() {}
+SerialSetControlSignalsFunction::SerialSetControlSignalsFunction() = default;
+SerialSetControlSignalsFunction::~SerialSetControlSignalsFunction() = default;
 
-SerialSetControlSignalsFunction::~SerialSetControlSignalsFunction() {}
+ExtensionFunction::ResponseAction SerialSetControlSignalsFunction::Run() {
+  auto params = serial::SetControlSignals::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
-bool SerialSetControlSignalsFunction::Prepare() {
-  params_ = serial::SetControlSignals::Params::Create(*args_);
-  EXTENSION_FUNCTION_VALIDATE(params_.get());
-
-  return true;
-}
-
-void SerialSetControlSignalsFunction::AsyncWorkStart() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  SerialConnection* connection = GetSerialConnection(params_->connection_id);
-  if (!connection) {
-    error_ = kErrorSerialConnectionNotFound;
-    AsyncWorkCompleted();
-    return;
-  }
+  SerialConnection* connection = GetSerialConnection(params->connection_id);
+  if (!connection)
+    return RespondNow(Error(kErrorSerialConnectionNotFound));
 
   connection->SetControlSignals(
-      device::mojom::SerialHostControlSignals::From(params_->signals),
+      device::mojom::SerialHostControlSignals::From(params->signals),
       base::BindOnce(&SerialSetControlSignalsFunction::OnSetControlSignals,
                      this));
+  return RespondLater();
 }
 
 void SerialSetControlSignalsFunction::OnSetControlSignals(bool success) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  results_ = serial::SetControlSignals::Results::Create(success);
-  AsyncWorkCompleted();
+  Respond(OneArgument(std::make_unique<base::Value>(success)));
 }
 
-SerialSetBreakFunction::SerialSetBreakFunction() {}
+SerialSetBreakFunction::SerialSetBreakFunction() = default;
+SerialSetBreakFunction::~SerialSetBreakFunction() = default;
 
-SerialSetBreakFunction::~SerialSetBreakFunction() {}
+ExtensionFunction::ResponseAction SerialSetBreakFunction::Run() {
+  auto params = serial::SetBreak::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
-bool SerialSetBreakFunction::Prepare() {
-  params_ = serial::SetBreak::Params::Create(*args_);
-  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  SerialConnection* connection = GetSerialConnection(params->connection_id);
+  if (!connection)
+    return RespondNow(Error(kErrorSerialConnectionNotFound));
 
-  return true;
-}
-
-void SerialSetBreakFunction::AsyncWorkStart() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  SerialConnection* connection = GetSerialConnection(params_->connection_id);
-  if (!connection) {
-    error_ = kErrorSerialConnectionNotFound;
-    AsyncWorkCompleted();
-    return;
-  }
   auto signals = device::mojom::SerialHostControlSignals::New();
   signals->has_brk = true;
   signals->brk = true;
   connection->SetControlSignals(
       std::move(signals),
       base::BindOnce(&SerialSetBreakFunction::OnSetBreak, this));
+  return RespondLater();
 }
 
 void SerialSetBreakFunction::OnSetBreak(bool success) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  results_ = serial::SetBreak::Results::Create(success);
-  AsyncWorkCompleted();
+  Respond(OneArgument(std::make_unique<base::Value>(success)));
 }
 
-SerialClearBreakFunction::SerialClearBreakFunction() {}
+SerialClearBreakFunction::SerialClearBreakFunction() = default;
+SerialClearBreakFunction::~SerialClearBreakFunction() = default;
 
-SerialClearBreakFunction::~SerialClearBreakFunction() {}
+ExtensionFunction::ResponseAction SerialClearBreakFunction::Run() {
+  auto params = serial::ClearBreak::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
-bool SerialClearBreakFunction::Prepare() {
-  params_ = serial::ClearBreak::Params::Create(*args_);
-  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  SerialConnection* connection = GetSerialConnection(params->connection_id);
+  if (!connection)
+    return RespondNow(Error(kErrorSerialConnectionNotFound));
 
-  return true;
-}
-
-void SerialClearBreakFunction::AsyncWorkStart() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  SerialConnection* connection = GetSerialConnection(params_->connection_id);
-  if (!connection) {
-    error_ = kErrorSerialConnectionNotFound;
-    AsyncWorkCompleted();
-    return;
-  }
   auto signals = device::mojom::SerialHostControlSignals::New();
   signals->has_brk = true;
   signals->brk = false;
   connection->SetControlSignals(
       std::move(signals),
       base::BindOnce(&SerialClearBreakFunction::OnClearBreak, this));
+  return RespondLater();
 }
 
 void SerialClearBreakFunction::OnClearBreak(bool success) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  results_ = serial::ClearBreak::Results::Create(success);
-  AsyncWorkCompleted();
+  Respond(OneArgument(std::make_unique<base::Value>(success)));
 }
 
 }  // namespace api
diff --git a/extensions/browser/api/serial/serial_api.h b/extensions/browser/api/serial/serial_api.h
index 1551c60..12e4876 100644
--- a/extensions/browser/api/serial/serial_api.h
+++ b/extensions/browser/api/serial/serial_api.h
@@ -9,8 +9,7 @@
 #include <string>
 #include <vector>
 
-#include "extensions/browser/api/api_resource_manager.h"
-#include "extensions/browser/api/async_api_function.h"
+#include "extensions/browser/extension_function.h"
 #include "extensions/common/api/serial.h"
 #include "services/device/public/mojom/serial.mojom.h"
 
@@ -20,23 +19,15 @@
 
 namespace api {
 
-class SerialPortManager;
-
-class SerialAsyncApiFunction : public AsyncApiFunction {
+class SerialExtensionFunction : public ExtensionFunction {
  public:
-  SerialAsyncApiFunction();
+  SerialExtensionFunction();
 
  protected:
-  ~SerialAsyncApiFunction() override;
-
-  // AsyncApiFunction:
-  bool PrePrepare() override;
-  bool Respond() override;
+  ~SerialExtensionFunction() override;
 
   SerialConnection* GetSerialConnection(int api_resource_id);
   void RemoveSerialConnection(int api_resource_id);
-
-  ApiResourceManager<SerialConnection>* manager_;
 };
 
 class SerialGetDevicesFunction : public ExtensionFunction {
@@ -48,7 +39,7 @@
  protected:
   ~SerialGetDevicesFunction() override;
 
-  // ExtensionFunction:
+  // ExtensionFunction
   ResponseAction Run() override;
 
  private:
@@ -57,7 +48,7 @@
   DISALLOW_COPY_AND_ASSIGN(SerialGetDevicesFunction);
 };
 
-class SerialConnectFunction : public SerialAsyncApiFunction {
+class SerialConnectFunction : public SerialExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("serial.connect", SERIAL_CONNECT)
 
@@ -66,9 +57,8 @@
  protected:
   ~SerialConnectFunction() override;
 
-  // AsyncApiFunction:
-  bool Prepare() override;
-  void AsyncWorkStart() override;
+  // ExtensionFunction
+  ResponseAction Run() override;
 
  private:
   void OnConnected(bool success);
@@ -76,20 +66,13 @@
                      bool got_complete_info,
                      std::unique_ptr<serial::ConnectionInfo> info);
 
-  std::unique_ptr<serial::Connect::Params> params_;
-
-  // SerialPortManager is owned by a BrowserContext.
-  SerialPortManager* serial_port_manager_;
-
   // This connection is created within SerialConnectFunction.
   // From there its ownership is transferred to the
   // ApiResourceManager<SerialConnection> upon success.
   std::unique_ptr<SerialConnection> connection_;
-
-  device::mojom::SerialPortPtrInfo serial_port_info_;
 };
 
-class SerialUpdateFunction : public SerialAsyncApiFunction {
+class SerialUpdateFunction : public SerialExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("serial.update", SERIAL_UPDATE)
 
@@ -98,17 +81,14 @@
  protected:
   ~SerialUpdateFunction() override;
 
-  // AsyncApiFunction:
-  bool Prepare() override;
-  void AsyncWorkStart() override;
+  // ExtensionFunction
+  ResponseAction Run() override;
 
  private:
   void OnUpdated(bool success);
-
-  std::unique_ptr<serial::Update::Params> params_;
 };
 
-class SerialDisconnectFunction : public SerialAsyncApiFunction {
+class SerialDisconnectFunction : public SerialExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("serial.disconnect", SERIAL_DISCONNECT)
 
@@ -117,17 +97,14 @@
  protected:
   ~SerialDisconnectFunction() override;
 
-  // AsyncApiFunction:
-  bool Prepare() override;
-  void AsyncWorkStart() override;
+  // ExtensionFunction
+  ResponseAction Run() override;
 
  private:
-  void OnCloseComplete();
-
-  std::unique_ptr<serial::Disconnect::Params> params_;
+  void OnCloseComplete(int connection_id);
 };
 
-class SerialSetPausedFunction : public SerialAsyncApiFunction {
+class SerialSetPausedFunction : public SerialExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("serial.setPaused", SERIAL_SETPAUSED)
 
@@ -136,16 +113,11 @@
  protected:
   ~SerialSetPausedFunction() override;
 
-  // AsyncApiFunction:
-  bool Prepare() override;
-  void Work() override;
-
- private:
-  std::unique_ptr<serial::SetPaused::Params> params_;
-  SerialPortManager* serial_port_manager_;
+  // ExtensionFunction
+  ResponseAction Run() override;
 };
 
-class SerialGetInfoFunction : public SerialAsyncApiFunction {
+class SerialGetInfoFunction : public SerialExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("serial.getInfo", SERIAL_GETINFO)
 
@@ -154,18 +126,16 @@
  protected:
   ~SerialGetInfoFunction() override;
 
-  // AsyncApiFunction:
-  bool Prepare() override;
-  void AsyncWorkStart() override;
+  // ExtensionFunction
+  ResponseAction Run() override;
 
  private:
-  void OnGotInfo(bool got_complete_info,
+  void OnGotInfo(int connection_id,
+                 bool got_complete_info,
                  std::unique_ptr<serial::ConnectionInfo> info);
-
-  std::unique_ptr<serial::GetInfo::Params> params_;
 };
 
-class SerialGetConnectionsFunction : public SerialAsyncApiFunction {
+class SerialGetConnectionsFunction : public SerialExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("serial.getConnections", SERIAL_GETCONNECTIONS)
 
@@ -174,9 +144,8 @@
  protected:
   ~SerialGetConnectionsFunction() override;
 
-  // AsyncApiFunction:
-  bool Prepare() override;
-  void AsyncWorkStart() override;
+  // ExtensionFunction
+  ResponseAction Run() override;
 
  private:
   void OnGotOne(int connection_id,
@@ -188,7 +157,7 @@
   std::vector<serial::ConnectionInfo> infos_;
 };
 
-class SerialSendFunction : public SerialAsyncApiFunction {
+class SerialSendFunction : public SerialExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("serial.send", SERIAL_SEND)
 
@@ -197,17 +166,14 @@
  protected:
   ~SerialSendFunction() override;
 
-  // AsyncApiFunction:
-  bool Prepare() override;
-  void AsyncWorkStart() override;
+  // ExtensionFunction
+  ResponseAction Run() override;
 
  private:
   void OnSendComplete(uint32_t bytes_sent, serial::SendError error);
-
-  std::unique_ptr<serial::Send::Params> params_;
 };
 
-class SerialFlushFunction : public SerialAsyncApiFunction {
+class SerialFlushFunction : public SerialExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("serial.flush", SERIAL_FLUSH)
 
@@ -216,17 +182,14 @@
  protected:
   ~SerialFlushFunction() override;
 
-  // AsyncApiFunction:
-  bool Prepare() override;
-  void AsyncWorkStart() override;
+  // ExtensionFunction
+  ResponseAction Run() override;
 
  private:
   void OnFlushed(bool success);
-
-  std::unique_ptr<serial::Flush::Params> params_;
 };
 
-class SerialGetControlSignalsFunction : public SerialAsyncApiFunction {
+class SerialGetControlSignalsFunction : public SerialExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("serial.getControlSignals",
                              SERIAL_GETCONTROLSIGNALS)
@@ -236,18 +199,15 @@
  protected:
   ~SerialGetControlSignalsFunction() override;
 
-  // AsyncApiFunction:
-  bool Prepare() override;
-  void AsyncWorkStart() override;
+  // ExtensionFunction
+  ResponseAction Run() override;
 
  private:
   void OnGotControlSignals(
       std::unique_ptr<serial::DeviceControlSignals> signals);
-
-  std::unique_ptr<serial::GetControlSignals::Params> params_;
 };
 
-class SerialSetControlSignalsFunction : public SerialAsyncApiFunction {
+class SerialSetControlSignalsFunction : public SerialExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("serial.setControlSignals",
                              SERIAL_SETCONTROLSIGNALS)
@@ -257,17 +217,14 @@
  protected:
   ~SerialSetControlSignalsFunction() override;
 
-  // AsyncApiFunction:
-  bool Prepare() override;
-  void AsyncWorkStart() override;
+  // ExtensionFunction
+  ResponseAction Run() override;
 
  private:
   void OnSetControlSignals(bool success);
-
-  std::unique_ptr<serial::SetControlSignals::Params> params_;
 };
 
-class SerialSetBreakFunction : public SerialAsyncApiFunction {
+class SerialSetBreakFunction : public SerialExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("serial.setBreak", SERIAL_SETBREAK)
   SerialSetBreakFunction();
@@ -275,17 +232,14 @@
  protected:
   ~SerialSetBreakFunction() override;
 
-  // AsyncApiFunction:
-  bool Prepare() override;
-  void AsyncWorkStart() override;
+  // ExtensionFunction
+  ResponseAction Run() override;
 
  private:
   void OnSetBreak(bool success);
-
-  std::unique_ptr<serial::SetBreak::Params> params_;
 };
 
-class SerialClearBreakFunction : public SerialAsyncApiFunction {
+class SerialClearBreakFunction : public SerialExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("serial.clearBreak", SERIAL_CLEARBREAK)
   SerialClearBreakFunction();
@@ -293,14 +247,11 @@
  protected:
   ~SerialClearBreakFunction() override;
 
-  // AsyncApiFunction:
-  bool Prepare() override;
-  void AsyncWorkStart() override;
+  // ExtensionFunction
+  ResponseAction Run() override;
 
  private:
   void OnClearBreak(bool success);
-
-  std::unique_ptr<serial::ClearBreak::Params> params_;
 };
 
 }  // namespace api
diff --git a/extensions/browser/api/serial/serial_connection.cc b/extensions/browser/api/serial/serial_connection.cc
index 9233060e..ce754cf 100644
--- a/extensions/browser/api/serial/serial_connection.cc
+++ b/extensions/browser/api/serial/serial_connection.cc
@@ -158,9 +158,8 @@
   return g_factory.Pointer();
 }
 
-SerialConnection::SerialConnection(
-    const std::string& owner_extension_id,
-    device::mojom::SerialPortPtrInfo serial_port_info)
+SerialConnection::SerialConnection(const std::string& owner_extension_id,
+                                   device::mojom::SerialPortPtr serial_port)
     : ApiResource(owner_extension_id),
       persistent_(false),
       buffer_size_(kDefaultBufferSize),
@@ -169,13 +168,12 @@
       paused_(true),
       read_error_(base::nullopt),
       bytes_written_(0),
+      serial_port_(std::move(serial_port)),
       receive_pipe_watcher_(FROM_HERE,
                             mojo::SimpleWatcher::ArmingPolicy::MANUAL),
       send_pipe_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
       client_binding_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK(serial_port_info.is_valid());
-  serial_port_.Bind(std::move(serial_port_info));
+  DCHECK(serial_port_);
   serial_port_.set_connection_error_handler(base::BindOnce(
       &SerialConnection::OnConnectionError, base::Unretained(this)));
 }
@@ -232,7 +230,6 @@
 
 void SerialConnection::Open(const api::serial::ConnectionOptions& options,
                             OpenCompleteCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(serial_port_);
   DCHECK(!send_pipe_);
   DCHECK(!receive_pipe_);
@@ -363,7 +360,6 @@
 void SerialConnection::OnReadPipeReadableOrClosed(
     MojoResult result,
     const mojo::HandleSignalsState& state) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   // Data pipe disconnected.
   if (result != MOJO_RESULT_OK) {
     OnReadPipeClosed();
@@ -401,7 +397,6 @@
 }
 
 void SerialConnection::StartPolling(const ReceiveEventCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   receive_event_cb_ = callback;
   DCHECK(receive_event_cb_);
   DCHECK(receive_pipe_);
@@ -411,7 +406,6 @@
 
 bool SerialConnection::Send(const std::vector<uint8_t>& data,
                             SendCompleteCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (send_complete_)
     return false;
 
@@ -444,7 +438,6 @@
 
 void SerialConnection::Configure(const api::serial::ConnectionOptions& options,
                                  ConfigureCompleteCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(serial_port_);
   if (options.persistent.get())
     set_persistent(*options.persistent);
@@ -462,7 +455,6 @@
 }
 
 void SerialConnection::GetInfo(GetInfoCompleteCallback callback) const {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(serial_port_);
 
   auto info = std::make_unique<api::serial::ConnectionInfo>();
@@ -540,8 +532,6 @@
 }
 
 void SerialConnection::SetTimeoutCallback() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
   if (receive_timeout_ > 0) {
     receive_timeout_task_.Reset(base::Bind(&SerialConnection::OnReceiveTimeout,
                                            weak_factory_.GetWeakPtr()));
@@ -552,14 +542,12 @@
 }
 
 void SerialConnection::OnReceiveTimeout() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(serial_port_);
   receive_event_cb_.Run(std::vector<uint8_t>(),
                         api::serial::RECEIVE_ERROR_TIMEOUT);
 }
 
 void SerialConnection::OnSendTimeout() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(serial_port_);
   if (send_complete_) {
     send_pipe_watcher_.Cancel();
@@ -574,7 +562,6 @@
 void SerialConnection::OnSendPipeWritableOrClosed(
     MojoResult result,
     const mojo::HandleSignalsState& state) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   // Data pipe disconnected.
   if (result != MOJO_RESULT_OK) {
     OnSendPipeClosed();
diff --git a/extensions/browser/api/serial/serial_connection.h b/extensions/browser/api/serial/serial_connection.h
index a2565bd..9dfd77e 100644
--- a/extensions/browser/api/serial/serial_connection.h
+++ b/extensions/browser/api/serial/serial_connection.h
@@ -65,7 +65,7 @@
       device::mojom::SerialPort::SetControlSignalsCallback;
 
   SerialConnection(const std::string& owner_extension_id,
-                   device::mojom::SerialPortPtrInfo serial_port_info);
+                   device::mojom::SerialPortPtr serial_port);
   ~SerialConnection() override;
 
   // ApiResource override.
@@ -132,7 +132,7 @@
   // Initiates an asynchronous close of the device.
   void Close(base::OnceClosure callback);
 
-  static const BrowserThread::ID kThreadId = BrowserThread::IO;
+  static const BrowserThread::ID kThreadId = BrowserThread::UI;
 
  private:
   friend class ApiResourceManager<SerialConnection>;
diff --git a/extensions/browser/api/serial/serial_port_manager.cc b/extensions/browser/api/serial/serial_port_manager.cc
index d69c55a..448e339 100644
--- a/extensions/browser/api/serial/serial_port_manager.cc
+++ b/extensions/browser/api/serial/serial_port_manager.cc
@@ -8,7 +8,6 @@
 
 #include "base/bind.h"
 #include "base/lazy_instance.h"
-#include "base/task/post_task.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/system_connector.h"
@@ -52,7 +51,7 @@
 }
 
 SerialPortManager::SerialPortManager(content::BrowserContext* context)
-    : thread_id_(SerialConnection::kThreadId), context_(context) {
+    : context_(context) {
   ApiResourceManager<SerialConnection>* manager =
       ApiResourceManager<SerialConnection>::Get(context_);
   DCHECK(manager) << "No serial connection manager.";
@@ -70,12 +69,14 @@
 
 void SerialPortManager::GetDevices(
     device::mojom::SerialPortManager::GetDevicesCallback callback) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   EnsureConnection();
   port_manager_->GetDevices(std::move(callback));
 }
 
 void SerialPortManager::GetPort(const std::string& path,
                                 device::mojom::SerialPortRequest request) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   EnsureConnection();
   port_manager_->GetDevices(
       base::BindOnce(&SerialPortManager::OnGotDevicesToGetPort,
@@ -84,7 +85,7 @@
 
 void SerialPortManager::StartConnectionPolling(const std::string& extension_id,
                                                int connection_id) {
-  DCHECK_CURRENTLY_ON(thread_id_);
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   auto* connection = connections_->Get(extension_id, connection_id);
   if (!connection)
     return;
@@ -92,7 +93,6 @@
   DCHECK_EQ(extension_id, connection->owner_extension_id());
 
   ReceiveParams params;
-  params.thread_id = thread_id_;
   params.browser_context_id = context_;
   params.extension_id = extension_id;
   params.connections = connections_;
@@ -105,8 +105,6 @@
 void SerialPortManager::DispatchReceiveEvent(const ReceiveParams& params,
                                              std::vector<uint8_t> data,
                                              serial::ReceiveError error) {
-  DCHECK_CURRENTLY_ON(params.thread_id);
-
   // Note that an error (e.g. timeout) does not necessarily mean that no data
   // was read, so we may fire an onReceive regardless of any error code.
   if (data.size() > 0) {
@@ -118,10 +116,16 @@
     std::unique_ptr<extensions::Event> event(
         new extensions::Event(extensions::events::SERIAL_ON_RECEIVE,
                               serial::OnReceive::kEventName, std::move(args)));
-    PostEvent(params, std::move(event));
+    DispatchEvent(params, std::move(event));
   }
 
   if (error != serial::RECEIVE_ERROR_NONE) {
+    if (ShouldPauseOnReceiveError(error)) {
+      SerialConnection* connection =
+          params.connections->Get(params.extension_id, params.connection_id);
+      if (connection)
+        connection->SetPaused(true);
+    }
     serial::ReceiveErrorInfo error_info;
     error_info.connection_id = params.connection_id;
     error_info.error = error;
@@ -130,41 +134,22 @@
     std::unique_ptr<extensions::Event> event(new extensions::Event(
         extensions::events::SERIAL_ON_RECEIVE_ERROR,
         serial::OnReceiveError::kEventName, std::move(args)));
-    PostEvent(params, std::move(event));
-    if (ShouldPauseOnReceiveError(error)) {
-      SerialConnection* connection =
-          params.connections->Get(params.extension_id, params.connection_id);
-      if (connection)
-        connection->SetPaused(true);
-    }
+    DispatchEvent(params, std::move(event));
   }
 }
 
 // static
-void SerialPortManager::PostEvent(const ReceiveParams& params,
-                                  std::unique_ptr<extensions::Event> event) {
-  DCHECK_CURRENTLY_ON(params.thread_id);
-
-  base::PostTask(FROM_HERE, {BrowserThread::UI},
-                 base::BindOnce(&DispatchEvent, params.browser_context_id,
-                                params.extension_id, std::move(event)));
-}
-
-// static
 void SerialPortManager::DispatchEvent(
-    void* browser_context_id,
-    const std::string& extension_id,
+    const ReceiveParams& params,
     std::unique_ptr<extensions::Event> event) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
   content::BrowserContext* context =
-      reinterpret_cast<content::BrowserContext*>(browser_context_id);
+      reinterpret_cast<content::BrowserContext*>(params.browser_context_id);
   if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context))
     return;
 
   EventRouter* router = EventRouter::Get(context);
   if (router)
-    router->DispatchEventToExtension(extension_id, std::move(event));
+    router->DispatchEventToExtension(params.extension_id, std::move(event));
 }
 
 void SerialPortManager::EnsureConnection() {
@@ -172,7 +157,6 @@
   if (port_manager_)
     return;
 
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(content::GetSystemConnector());
   content::GetSystemConnector()->BindInterface(
       device::mojom::kServiceName, mojo::MakeRequest(&port_manager_));
diff --git a/extensions/browser/api/serial/serial_port_manager.h b/extensions/browser/api/serial/serial_port_manager.h
index 5c834bd..ab81779 100644
--- a/extensions/browser/api/serial/serial_port_manager.h
+++ b/extensions/browser/api/serial/serial_port_manager.h
@@ -61,7 +61,6 @@
     ReceiveParams(const ReceiveParams& other);
     ~ReceiveParams();
 
-    content::BrowserThread::ID thread_id;
     void* browser_context_id;
     std::string extension_id;
     scoped_refptr<ConnectionData> connections;
@@ -71,11 +70,7 @@
                                    std::vector<uint8_t> data,
                                    serial::ReceiveError error);
 
-  static void PostEvent(const ReceiveParams& params,
-                        std::unique_ptr<extensions::Event> event);
-
-  static void DispatchEvent(void* browser_context_id,
-                            const std::string& extension_id,
+  static void DispatchEvent(const ReceiveParams& params,
                             std::unique_ptr<extensions::Event> event);
 
   void EnsureConnection();
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index b692888..fd4bcdb 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -13,6 +13,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/containers/flat_map.h"
 #include "base/json/json_writer.h"
 #include "base/lazy_instance.h"
 #include "base/metrics/histogram_macros.h"
@@ -187,18 +188,56 @@
                             RequestAction::MAX);
 }
 
-bool IsWebRequestEvent(const std::string& event_name) {
-  std::string web_request_event_name(event_name);
-  if (base::StartsWith(web_request_event_name,
-                       webview::kWebViewEventPrefix,
-                       base::CompareCase::SENSITIVE)) {
-    web_request_event_name.replace(
-        0, strlen(webview::kWebViewEventPrefix), kWebRequestEventPrefix);
-  }
-  auto* const* web_request_events_end =
-      kWebRequestEvents + base::size(kWebRequestEvents);
-  return std::find(kWebRequestEvents, web_request_events_end,
-                   web_request_event_name) != web_request_events_end;
+// Returns the corresponding EventTypes for the given |event_name|. If
+// |event_name| is an invalid event, returns EventTypes::kInvalidEvent.
+ExtensionWebRequestEventRouter::EventTypes GetEventTypeFromEventName(
+    base::StringPiece event_name) {
+  static const base::flat_map<base::StringPiece,
+                              ExtensionWebRequestEventRouter::EventTypes>
+      kRequestStageMap(
+          {{keys::kOnBeforeRequest,
+            ExtensionWebRequestEventRouter::kOnBeforeRequest},
+           {keys::kOnBeforeSendHeaders,
+            ExtensionWebRequestEventRouter::kOnBeforeSendHeaders},
+           {keys::kOnSendHeaders,
+            ExtensionWebRequestEventRouter::kOnSendHeaders},
+           {keys::kOnHeadersReceived,
+            ExtensionWebRequestEventRouter::kOnHeadersReceived},
+           {keys::kOnBeforeRedirect,
+            ExtensionWebRequestEventRouter::kOnBeforeRedirect},
+           {keys::kOnAuthRequired,
+            ExtensionWebRequestEventRouter::kOnAuthRequired},
+           {keys::kOnResponseStarted,
+            ExtensionWebRequestEventRouter::kOnResponseStarted},
+           {keys::kOnErrorOccurred,
+            ExtensionWebRequestEventRouter::kOnErrorOccurred},
+           {keys::kOnCompleted, ExtensionWebRequestEventRouter::kOnCompleted}});
+
+  DCHECK_EQ(kRequestStageMap.size(), base::size(kWebRequestEvents));
+
+  static const size_t kWebRequestEventPrefixLen =
+      strlen(kWebRequestEventPrefix);
+  static const size_t kWebViewEventPrefixLen =
+      strlen(webview::kWebViewEventPrefix);
+
+  // Canonicalize the |event_name| to the request stage.
+  if (event_name.starts_with(kWebRequestEventPrefix))
+    event_name.remove_prefix(kWebRequestEventPrefixLen);
+  else if (event_name.starts_with(webview::kWebViewEventPrefix))
+    event_name.remove_prefix(kWebViewEventPrefixLen);
+  else
+    return ExtensionWebRequestEventRouter::kInvalidEvent;
+
+  auto it = kRequestStageMap.find(event_name);
+  if (it == kRequestStageMap.end())
+    return ExtensionWebRequestEventRouter::kInvalidEvent;
+
+  return it->second;
+}
+
+bool IsWebRequestEvent(base::StringPiece event_name) {
+  return GetEventTypeFromEventName(event_name) !=
+         ExtensionWebRequestEventRouter::kInvalidEvent;
 }
 
 // Returns whether |request| has been triggered by an extension enabled in
@@ -1015,40 +1054,6 @@
 
   const bool is_incognito_context = IsIncognitoBrowserContext(browser_context);
 
-  // Handle Declarative Net Request API rules. This gets preference over the Web
-  // Request and Declarative Web Request APIs. Only checking the rules in the
-  // OnBeforeRequest stage works, since the rules currently only depend on the
-  // request url, initiator and resource type, which should stay the same during
-  // the diffierent network request stages. A redirect should cause another
-  // OnBeforeRequest call.
-  const Action& action =
-      declarative_net_request::RulesMonitorService::Get(browser_context)
-          ->ruleset_manager()
-          ->EvaluateRequest(*request, is_incognito_context);
-  switch (action.type) {
-    case Action::Type::NONE:
-      break;
-    case Action::Type::BLOCK:
-      OnDNRActionMatched(browser_context, *request);
-      return net::ERR_BLOCKED_BY_CLIENT;
-    case Action::Type::COLLAPSE:
-      OnDNRActionMatched(browser_context, *request);
-      *should_collapse_initiator = true;
-      return net::ERR_BLOCKED_BY_CLIENT;
-    case Action::Type::REDIRECT:
-      DCHECK(action.redirect_url);
-      OnDNRActionMatched(browser_context, *request);
-      *new_url = action.redirect_url.value();
-      return net::OK;
-    case Action::Type::REMOVE_HEADERS:
-      // Unlike other actions, allow web request extensions to intercept the
-      // request here. The headers will be removed during subsequent request
-      // stages.
-      DCHECK(request->dnr_action.has_value());
-      DCHECK_EQ(request->dnr_action->type, Action::Type::REMOVE_HEADERS);
-      break;
-  }
-
   // Whether to initialized |blocked_requests_|.
   bool initialize_blocked_requests = false;
 
@@ -1069,6 +1074,45 @@
         browser_context, request, listeners, std::move(event_details));
   }
 
+  // Handle Declarative Net Request API rules. In case the request is blocked or
+  // redirected, we un-block the request and ignore any subsequent responses
+  // from webRequestBlocking listeners. Note: We don't remove the request from
+  // the |EventListener::blocked_requests| set of any blocking listeners it was
+  // dispatched to, since the listener's response will be ignored in
+  // |DecrementBlockCount| anyway.
+
+  // Only checking the rules in the OnBeforeRequest stage works, since the rules
+  // currently only depend on the request url, initiator and resource type,
+  // which should stay the same during the diffierent network request stages. A
+  // redirect should cause another OnBeforeRequest call.
+  const Action& action =
+      declarative_net_request::RulesMonitorService::Get(browser_context)
+          ->ruleset_manager()
+          ->EvaluateRequest(*request, is_incognito_context);
+  switch (action.type) {
+    case Action::Type::NONE:
+      break;
+    case Action::Type::BLOCK:
+      ClearPendingCallbacks(*request);
+      OnDNRActionMatched(browser_context, *request);
+      return net::ERR_BLOCKED_BY_CLIENT;
+    case Action::Type::COLLAPSE:
+      ClearPendingCallbacks(*request);
+      OnDNRActionMatched(browser_context, *request);
+      *should_collapse_initiator = true;
+      return net::ERR_BLOCKED_BY_CLIENT;
+    case Action::Type::REDIRECT:
+      ClearPendingCallbacks(*request);
+      DCHECK(action.redirect_url);
+      OnDNRActionMatched(browser_context, *request);
+      *new_url = action.redirect_url.value();
+      return net::OK;
+    case Action::Type::REMOVE_HEADERS:
+      DCHECK(request->dnr_action.has_value());
+      DCHECK_EQ(request->dnr_action->type, Action::Type::REMOVE_HEADERS);
+      break;
+  }
+
   if (!initialize_blocked_requests)
     return net::OK;  // Nobody saw a reason for modifying the request.
 
@@ -2145,12 +2189,17 @@
   std::unique_ptr<EventResponse> response_scoped(response);
 
   // It's possible that this request was deleted, or cancelled by a previous
-  // event handler. If so, ignore this response.
+  // event handler or handled by Declarative Net Request API. If so, ignore this
+  // response.
   auto it = blocked_requests_.find(request_id);
   if (it == blocked_requests_.end())
     return;
 
   BlockedRequest& blocked_request = it->second;
+
+  // Ensure that the response is for the event we are blocked on.
+  DCHECK_EQ(blocked_request.event, GetEventTypeFromEventName(event_name));
+
   int num_handlers_blocking = --blocked_request.num_handlers_blocking;
   CHECK_GE(num_handlers_blocking, 0);
 
@@ -2166,9 +2215,8 @@
     blocked_request.response_deltas.push_back(std::move(delta));
   }
 
-  if (num_handlers_blocking == 0) {
+  if (num_handlers_blocking == 0)
     ExecuteDeltas(browser_context, blocked_request.request, true);
-  }
 }
 
 void ExtensionWebRequestEventRouter::SendMessages(
diff --git a/extensions/browser/api/webcam_private/visca_webcam.cc b/extensions/browser/api/webcam_private/visca_webcam.cc
index a88ec80..fba8b44 100644
--- a/extensions/browser/api/webcam_private/visca_webcam.cc
+++ b/extensions/browser/api/webcam_private/visca_webcam.cc
@@ -10,14 +10,7 @@
 #include <algorithm>
 
 #include "base/bind.h"
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
-#include "base/task/post_task.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
 
 using content::BrowserThread;
 
@@ -160,25 +153,13 @@
 
 namespace extensions {
 
-ViscaWebcam::ViscaWebcam() : pan_(0), tilt_(0) {}
+ViscaWebcam::ViscaWebcam() = default;
 
-ViscaWebcam::~ViscaWebcam() {
-}
+ViscaWebcam::~ViscaWebcam() = default;
 
 void ViscaWebcam::Open(const std::string& extension_id,
-                       device::mojom::SerialPortPtrInfo port_ptr_info,
+                       device::mojom::SerialPortPtr port_ptr,
                        const OpenCompleteCallback& open_callback) {
-  base::PostTask(FROM_HERE, {BrowserThread::IO},
-                 base::BindOnce(&ViscaWebcam::OpenOnIOThread,
-                                weak_ptr_factory_.GetWeakPtr(), extension_id,
-                                std::move(port_ptr_info), open_callback));
-}
-
-void ViscaWebcam::OpenOnIOThread(const std::string& extension_id,
-                                 device::mojom::SerialPortPtrInfo port_ptr_info,
-                                 const OpenCompleteCallback& open_callback) {
-  CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
   api::serial::ConnectionOptions options;
 
   // Set the receive buffer size to receive the response data 1 by 1.
@@ -194,22 +175,22 @@
   options.stop_bits = api::serial::STOP_BITS_ONE;
 
   serial_connection_.reset(
-      new SerialConnection(extension_id, std::move(port_ptr_info)));
+      new SerialConnection(extension_id, std::move(port_ptr)));
   serial_connection_->Open(
-      options, base::BindOnce(&ViscaWebcam::OnConnected,
-                              weak_ptr_factory_.GetWeakPtr(), open_callback));
+      options, base::BindOnce(&ViscaWebcam::OnConnected, base::Unretained(this),
+                              open_callback));
 }
 
 void ViscaWebcam::OnConnected(const OpenCompleteCallback& open_callback,
                               bool success) {
   if (!success) {
-    PostOpenFailureTask(open_callback);
+    open_callback.Run(success);
     return;
   }
 
   Send(CHAR_VECTOR_FROM_ARRAY(kSetAddressCommand),
-       base::Bind(&ViscaWebcam::OnAddressSetCompleted,
-                  weak_ptr_factory_.GetWeakPtr(), open_callback));
+       base::Bind(&ViscaWebcam::OnAddressSetCompleted, base::Unretained(this),
+                  open_callback));
 }
 
 void ViscaWebcam::OnAddressSetCompleted(
@@ -218,26 +199,20 @@
     const std::vector<char>& response) {
   commands_.pop_front();
   if (!success) {
-    PostOpenFailureTask(open_callback);
+    open_callback.Run(success);
     return;
   }
 
   Send(CHAR_VECTOR_FROM_ARRAY(kClearAllCommand),
-       base::Bind(&ViscaWebcam::OnClearAllCompleted,
-                  weak_ptr_factory_.GetWeakPtr(), open_callback));
+       base::Bind(&ViscaWebcam::OnClearAllCompleted, base::Unretained(this),
+                  open_callback));
 }
 
 void ViscaWebcam::OnClearAllCompleted(const OpenCompleteCallback& open_callback,
                                       bool success,
                                       const std::vector<char>& response) {
   commands_.pop_front();
-  if (!success) {
-    PostOpenFailureTask(open_callback);
-    return;
-  }
-
-  base::PostTask(FROM_HERE, {BrowserThread::UI},
-                 base::BindOnce(open_callback, true));
+  open_callback.Run(success);
 }
 
 void ViscaWebcam::Send(const std::vector<char>& command,
@@ -245,50 +220,36 @@
   commands_.push_back(std::make_pair(command, callback));
   // If this is the only command in the queue, send it now.
   if (commands_.size() == 1) {
-    base::PostTask(
-        FROM_HERE, {BrowserThread::IO},
-        base::BindOnce(&ViscaWebcam::SendOnIOThread,
-                       weak_ptr_factory_.GetWeakPtr(), command, callback));
+    serial_connection_->Send(
+        std::vector<uint8_t>(command.begin(), command.end()),
+        base::Bind(&ViscaWebcam::OnSendCompleted, base::Unretained(this),
+                   callback));
   }
 }
 
-void ViscaWebcam::SendOnIOThread(const std::vector<char>& data,
-                                 const CommandCompleteCallback& callback) {
-  CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  serial_connection_->Send(
-      std::vector<uint8_t>(data.begin(), data.end()),
-      base::Bind(&ViscaWebcam::OnSendCompleted, weak_ptr_factory_.GetWeakPtr(),
-                 callback));
-}
-
 void ViscaWebcam::OnSendCompleted(const CommandCompleteCallback& callback,
                                   uint32_t bytes_sent,
                                   api::serial::SendError error) {
-  CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   // TODO(xdai): Check |bytes_sent|?
   if (error == api::serial::SEND_ERROR_NONE) {
-    serial_connection_->StartPolling(
-        base::BindRepeating(&ViscaWebcam::OnReceiveEvent,
-                            weak_ptr_factory_.GetWeakPtr(), callback));
+    serial_connection_->StartPolling(base::BindRepeating(
+        &ViscaWebcam::OnReceiveEvent, base::Unretained(this), callback));
   } else {
-    base::PostTask(FROM_HERE, {BrowserThread::UI},
-                   base::BindOnce(callback, false, std::vector<char>()));
+    callback.Run(false, std::vector<char>());
   }
 }
 
 void ViscaWebcam::OnReceiveEvent(const CommandCompleteCallback& callback,
                                  std::vector<uint8_t> data,
                                  api::serial::ReceiveError error) {
-  CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   data_buffer_.insert(data_buffer_.end(), data.begin(), data.end());
 
   if (error != api::serial::RECEIVE_ERROR_NONE || data_buffer_.empty()) {
     // Clear |data_buffer_|.
     std::vector<char> response;
     response.swap(data_buffer_);
-    base::PostTask(FROM_HERE, {BrowserThread::UI},
-                   base::BindOnce(callback, false, response));
     serial_connection_->SetPaused(true);
+    callback.Run(false, response);
     return;
   }
 
@@ -304,22 +265,19 @@
 
   if (response.size() < 2 ||
       (static_cast<int>(response[1]) & 0xF0) == kViscaResponseError) {
-    base::PostTask(FROM_HERE, {BrowserThread::UI},
-                   base::BindOnce(callback, false, response));
     serial_connection_->SetPaused(true);
+    callback.Run(false, response);
   } else if ((static_cast<int>(response[1]) & 0xF0) != kViscaResponseAck &&
              (static_cast<int>(response[1]) & 0xFF) !=
                  kViscaResponseNetworkChange) {
-    base::PostTask(FROM_HERE, {BrowserThread::UI},
-                   base::BindOnce(callback, true, response));
     serial_connection_->SetPaused(true);
+    callback.Run(true, response);
   }
 }
 
 void ViscaWebcam::OnCommandCompleted(const SetPTZCompleteCallback& callback,
                                      bool success,
                                      const std::vector<char>& response) {
-  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   // TODO(xdai): Error handling according to |response|.
   callback.Run(success);
   ProcessNextCommand();
@@ -329,7 +287,6 @@
                                      const GetPTZCompleteCallback& callback,
                                      bool success,
                                      const std::vector<char>& response) {
-  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (!success) {
     callback.Run(false, 0 /* value */, 0 /* min_value */, 0 /* max_value */);
     ProcessNextCommand();
@@ -392,40 +349,34 @@
   // If there are pending commands, process the next one.
   const std::vector<char> next_command = commands_.front().first;
   const CommandCompleteCallback next_callback = commands_.front().second;
-  base::PostTask(FROM_HERE, {BrowserThread::IO},
-                 base::BindOnce(&ViscaWebcam::SendOnIOThread,
-                                weak_ptr_factory_.GetWeakPtr(), next_command,
-                                next_callback));
-}
-
-void ViscaWebcam::PostOpenFailureTask(
-    const OpenCompleteCallback& open_callback) {
-  base::PostTask(FROM_HERE, {BrowserThread::UI},
-                 base::BindOnce(open_callback, false /* success? */));
+  serial_connection_->Send(
+      std::vector<uint8_t>(next_command.begin(), next_command.end()),
+      base::Bind(&ViscaWebcam::OnSendCompleted, base::Unretained(this),
+                 next_callback));
 }
 
 void ViscaWebcam::GetPan(const GetPTZCompleteCallback& callback) {
   Send(CHAR_VECTOR_FROM_ARRAY(kGetPanTiltCommand),
-       base::Bind(&ViscaWebcam::OnInquiryCompleted,
-                  weak_ptr_factory_.GetWeakPtr(), INQUIRY_PAN, callback));
+       base::Bind(&ViscaWebcam::OnInquiryCompleted, base::Unretained(this),
+                  INQUIRY_PAN, callback));
 }
 
 void ViscaWebcam::GetTilt(const GetPTZCompleteCallback& callback) {
   Send(CHAR_VECTOR_FROM_ARRAY(kGetPanTiltCommand),
-       base::Bind(&ViscaWebcam::OnInquiryCompleted,
-                  weak_ptr_factory_.GetWeakPtr(), INQUIRY_TILT, callback));
+       base::Bind(&ViscaWebcam::OnInquiryCompleted, base::Unretained(this),
+                  INQUIRY_TILT, callback));
 }
 
 void ViscaWebcam::GetZoom(const GetPTZCompleteCallback& callback) {
   Send(CHAR_VECTOR_FROM_ARRAY(kGetZoomCommand),
-       base::Bind(&ViscaWebcam::OnInquiryCompleted,
-                  weak_ptr_factory_.GetWeakPtr(), INQUIRY_ZOOM, callback));
+       base::Bind(&ViscaWebcam::OnInquiryCompleted, base::Unretained(this),
+                  INQUIRY_ZOOM, callback));
 }
 
 void ViscaWebcam::GetFocus(const GetPTZCompleteCallback& callback) {
   Send(CHAR_VECTOR_FROM_ARRAY(kGetFocusCommand),
-       base::Bind(&ViscaWebcam::OnInquiryCompleted,
-                  weak_ptr_factory_.GetWeakPtr(), INQUIRY_FOCUS, callback));
+       base::Bind(&ViscaWebcam::OnInquiryCompleted, base::Unretained(this),
+                  INQUIRY_FOCUS, callback));
 }
 
 void ViscaWebcam::SetPan(int value,
@@ -441,7 +392,7 @@
   ResponseToCommand(&command, 6, static_cast<uint16_t>(pan_));
   ResponseToCommand(&command, 10, static_cast<uint16_t>(tilt_));
   Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
-                           weak_ptr_factory_.GetWeakPtr(), callback));
+                           base::Unretained(this), callback));
 }
 
 void ViscaWebcam::SetTilt(int value,
@@ -457,7 +408,7 @@
   ResponseToCommand(&command, 6, static_cast<uint16_t>(pan_));
   ResponseToCommand(&command, 10, static_cast<uint16_t>(tilt_));
   Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
-                           weak_ptr_factory_.GetWeakPtr(), callback));
+                           base::Unretained(this), callback));
 }
 
 void ViscaWebcam::SetZoom(int value, const SetPTZCompleteCallback& callback) {
@@ -465,7 +416,7 @@
   std::vector<char> command = CHAR_VECTOR_FROM_ARRAY(kSetZoomCommand);
   ResponseToCommand(&command, 4, actual_value);
   Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
-                           weak_ptr_factory_.GetWeakPtr(), callback));
+                           base::Unretained(this), callback));
 }
 
 void ViscaWebcam::SetFocus(int value, const SetPTZCompleteCallback& callback) {
@@ -473,7 +424,7 @@
   std::vector<char> command = CHAR_VECTOR_FROM_ARRAY(kSetFocusCommand);
   ResponseToCommand(&command, 4, actual_value);
   Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
-                           weak_ptr_factory_.GetWeakPtr(), callback));
+                           base::Unretained(this), callback));
 }
 
 void ViscaWebcam::SetAutofocusState(AutofocusState state,
@@ -485,7 +436,7 @@
     command = CHAR_VECTOR_FROM_ARRAY(kSetManualFocusCommand);
   }
   Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
-                           weak_ptr_factory_.GetWeakPtr(), callback));
+                           base::Unretained(this), callback));
 }
 
 void ViscaWebcam::SetPanDirection(PanDirection direction,
@@ -509,7 +460,7 @@
       break;
   }
   Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
-                           weak_ptr_factory_.GetWeakPtr(), callback));
+                           base::Unretained(this), callback));
 }
 
 void ViscaWebcam::SetTiltDirection(TiltDirection direction,
@@ -533,7 +484,7 @@
       break;
   }
   Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
-                           weak_ptr_factory_.GetWeakPtr(), callback));
+                           base::Unretained(this), callback));
 }
 
 void ViscaWebcam::Reset(bool pan,
@@ -543,8 +494,8 @@
   // pan and tilt are always reset together in Visca Webcams.
   if (pan || tilt) {
     Send(CHAR_VECTOR_FROM_ARRAY(kResetPanTiltCommand),
-         base::Bind(&ViscaWebcam::OnCommandCompleted,
-                    weak_ptr_factory_.GetWeakPtr(), callback));
+         base::Bind(&ViscaWebcam::OnCommandCompleted, base::Unretained(this),
+                    callback));
   }
   if (zoom) {
     // Set the default zoom value to 100 to be consistent with V4l2 webcam.
diff --git a/extensions/browser/api/webcam_private/visca_webcam.h b/extensions/browser/api/webcam_private/visca_webcam.h
index 65da7c2..9bdfe33 100644
--- a/extensions/browser/api/webcam_private/visca_webcam.h
+++ b/extensions/browser/api/webcam_private/visca_webcam.h
@@ -32,7 +32,7 @@
   // command buffer. After these three steps completes, |open_callback| will be
   // called.
   void Open(const std::string& extension_id,
-            device::mojom::SerialPortPtrInfo port_ptr_info,
+            device::mojom::SerialPortPtr port_ptr,
             const OpenCompleteCallback& open_callback);
 
  private:
@@ -51,10 +51,6 @@
   // Private because WebCam is base::RefCounted.
   ~ViscaWebcam() override;
 
-  void OpenOnIOThread(const std::string& extension_id,
-                      device::mojom::SerialPortPtrInfo port_ptr_info,
-                      const OpenCompleteCallback& open_callback);
-
   // Callback function that will be called after the serial connection has been
   // opened successfully.
   void OnConnected(const OpenCompleteCallback& open_callback, bool success);
@@ -74,8 +70,6 @@
   // Send or queue a command and wait for the camera's response.
   void Send(const std::vector<char>& command,
             const CommandCompleteCallback& callback);
-  void SendOnIOThread(const std::vector<char>& data,
-                      const CommandCompleteCallback& callback);
   void OnSendCompleted(const CommandCompleteCallback& callback,
                        uint32_t bytes_sent,
                        api::serial::SendError error);
@@ -96,7 +90,6 @@
                           const std::vector<char>& response);
 
   void ProcessNextCommand();
-  void PostOpenFailureTask(const OpenCompleteCallback& open_callback);
 
   // Webcam Overrides:
   void GetPan(const GetPTZCompleteCallback& callback) override;
@@ -142,10 +135,8 @@
 
   // Visca webcam always get/set pan-tilt together. |pan| and |tilt| are used to
   // store the current value of pan and tilt positions.
-  int pan_;
-  int tilt_;
-
-  base::WeakPtrFactory<ViscaWebcam> weak_ptr_factory_{this};
+  int pan_ = 0;
+  int tilt_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(ViscaWebcam);
 };
diff --git a/extensions/browser/api/webcam_private/visca_webcam_unittest.cc b/extensions/browser/api/webcam_private/visca_webcam_unittest.cc
index 596269c..0930bcc 100644
--- a/extensions/browser/api/webcam_private/visca_webcam_unittest.cc
+++ b/extensions/browser/api/webcam_private/visca_webcam_unittest.cc
@@ -19,8 +19,8 @@
 
 class TestSerialConnection : public SerialConnection {
  public:
-  explicit TestSerialConnection(device::mojom::SerialPortPtrInfo port_ptr_info)
-      : SerialConnection("dummy_id", std::move(port_ptr_info)) {}
+  explicit TestSerialConnection(device::mojom::SerialPortPtr port_ptr)
+      : SerialConnection("dummy_id", std::move(port_ptr)) {}
   ~TestSerialConnection() override {}
 
   void SetReceiveBuffer(const std::vector<uint8_t>& receive_buffer) {
@@ -103,11 +103,11 @@
 class ViscaWebcamTest : public testing::Test {
  protected:
   ViscaWebcamTest() {
-    device::mojom::SerialPortPtrInfo port_ptr_info;
-    mojo::MakeRequest(&port_ptr_info);
+    device::mojom::SerialPortPtr port_ptr;
+    mojo::MakeRequest(&port_ptr);
     webcam_ = new ViscaWebcam;
     webcam_->OpenForTesting(
-        std::make_unique<TestSerialConnection>(std::move(port_ptr_info)));
+        std::make_unique<TestSerialConnection>(std::move(port_ptr)));
   }
   ~ViscaWebcamTest() override {}
 
diff --git a/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc b/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
index 55d8ed9b..bb71674 100644
--- a/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
+++ b/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
@@ -79,17 +79,16 @@
     return false;
 
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  device::mojom::SerialPortPtrInfo port_ptr_info;
+  device::mojom::SerialPortPtr port_ptr;
   auto* port_manager = api::SerialPortManager::Get(browser_context_);
   DCHECK(port_manager);
-  port_manager->GetPort(device_path, mojo::MakeRequest(&port_ptr_info));
+  port_manager->GetPort(device_path, mojo::MakeRequest(&port_ptr));
 
-  ViscaWebcam* visca_webcam = new ViscaWebcam;
-  visca_webcam->Open(
-      extension_id, std::move(port_ptr_info),
-      base::Bind(&WebcamPrivateAPI::OnOpenSerialWebcam,
-                 weak_ptr_factory_.GetWeakPtr(), extension_id, device_path,
-                 base::WrapRefCounted(visca_webcam), callback));
+  auto visca_webcam = base::MakeRefCounted<ViscaWebcam>();
+  visca_webcam->Open(extension_id, std::move(port_ptr),
+                     base::Bind(&WebcamPrivateAPI::OnOpenSerialWebcam,
+                                weak_ptr_factory_.GetWeakPtr(), extension_id,
+                                device_path, visca_webcam, callback));
   return true;
 }
 
diff --git a/extensions/browser/blob_reader.cc b/extensions/browser/blob_reader.cc
index aa77368..492c339 100644
--- a/extensions/browser/blob_reader.cc
+++ b/extensions/browser/blob_reader.cc
@@ -15,13 +15,14 @@
                        const std::string& blob_uuid,
                        BlobReadCallback callback)
     : BlobReader(
-          content::BrowserContext::GetBlobPtr(browser_context, blob_uuid),
+          content::BrowserContext::GetBlobRemote(browser_context, blob_uuid),
           std::move(callback)) {}
 
-BlobReader::BlobReader(blink::mojom::BlobPtr blob, BlobReadCallback callback)
+BlobReader::BlobReader(mojo::PendingRemote<blink::mojom::Blob> blob,
+                       BlobReadCallback callback)
     : callback_(std::move(callback)), blob_(std::move(blob)) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  blob_.set_connection_error_handler(
+  blob_.set_disconnect_handler(
       base::BindOnce(&BlobReader::Failed, base::Unretained(this)));
 }
 
diff --git a/extensions/browser/blob_reader.h b/extensions/browser/blob_reader.h
index e0d72aa..fb3e6d5 100644
--- a/extensions/browser/blob_reader.h
+++ b/extensions/browser/blob_reader.h
@@ -12,7 +12,9 @@
 
 #include "base/callback.h"
 #include "base/macros.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/system/data_pipe_drainer.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom.h"
 #include "url/gurl.h"
@@ -36,7 +38,8 @@
   BlobReader(content::BrowserContext* browser_context,
              const std::string& blob_uuid,
              BlobReadCallback callback);
-  BlobReader(blink::mojom::BlobPtr blob, BlobReadCallback callback);
+  BlobReader(mojo::PendingRemote<blink::mojom::Blob> blob,
+             BlobReadCallback callback);
   ~BlobReader() override;
 
   void SetByteRange(int64_t offset, int64_t length);
@@ -57,7 +60,7 @@
   void Succeeded();
 
   BlobReadCallback callback_;
-  blink::mojom::BlobPtr blob_;
+  mojo::Remote<blink::mojom::Blob> blob_;
   struct Range {
     uint64_t offset;
     uint64_t length;
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
index c9de7fcd..8d03daef 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
@@ -244,8 +244,10 @@
 // to load a MimeHandlerView. The test passes if MHV loads. This is to catch the
 // potential race between the cross-origin renderer initiated navigation and
 // the navigation to "about:blank" started from the browser.
+//
+// Disabled due to flakiness: https://crbug.com/1002788.
 IN_PROC_BROWSER_TEST_P(MimeHandlerViewCrossProcessTest,
-                       NavigationRaceFromEmbedder) {
+                       DISABLED_NavigationRaceFromEmbedder) {
   if (!is_cross_process_mode()) {
     // Note that this test would pass trivially with BrowserPlugin-based guests
     // because loading a plugin is quite independent from navigating a plugin.
diff --git a/extensions/browser/image_sanitizer.cc b/extensions/browser/image_sanitizer.cc
index 1afbd08..861355aa8 100644
--- a/extensions/browser/image_sanitizer.cc
+++ b/extensions/browser/image_sanitizer.cc
@@ -91,8 +91,9 @@
     return;
   }
 
-  connector->BindInterface(service_filter, &image_decoder_ptr_);
-  image_decoder_ptr_.set_connection_error_handler(
+  connector->Connect(service_filter,
+                     image_decoder_.BindNewPipeAndPassReceiver());
+  image_decoder_.set_disconnect_handler(
       base::BindOnce(&ImageSanitizer::ReportError, weak_factory_.GetWeakPtr(),
                      Status::kServiceError, base::FilePath()));
 
@@ -143,7 +144,7 @@
     return;
   }
   const std::vector<uint8_t>& image_data = std::get<0>(read_and_delete_result);
-  image_decoder_ptr_->DecodeImage(
+  image_decoder_->DecodeImage(
       image_data, data_decoder::mojom::ImageCodec::DEFAULT,
       /*shrink_to_fit=*/false, kMaxImageCanvas, gfx::Size(),
       base::BindOnce(&ImageSanitizer::ImageDecoded, weak_factory_.GetWeakPtr(),
@@ -219,7 +220,7 @@
 }
 
 void ImageSanitizer::CleanUp() {
-  image_decoder_ptr_.reset();
+  image_decoder_.reset();
   // It's important to clear the repeating callback as it may cause a circular
   // reference (the callback holds a ref to an object that has a ref to |this|)
   // that would cause a leak.
diff --git a/extensions/browser/image_sanitizer.h b/extensions/browser/image_sanitizer.h
index a3b20e90..5988073 100644
--- a/extensions/browser/image_sanitizer.h
+++ b/extensions/browser/image_sanitizer.h
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/values.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/data_decoder/public/mojom/image_decoder.mojom.h"
 #include "services/service_manager/public/cpp/service_filter.h"
 
@@ -106,7 +107,7 @@
   std::set<base::FilePath> image_paths_;
   ImageDecodedCallback image_decoded_callback_;
   SanitizationDoneCallback done_callback_;
-  data_decoder::mojom::ImageDecoderPtr image_decoder_ptr_;
+  mojo::Remote<data_decoder::mojom::ImageDecoder> image_decoder_;
   base::WeakPtrFactory<ImageSanitizer> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ImageSanitizer);
diff --git a/extensions/common/api/declarative_net_request/test_utils.cc b/extensions/common/api/declarative_net_request/test_utils.cc
index eb436c08..8d4310bef 100644
--- a/extensions/common/api/declarative_net_request/test_utils.cc
+++ b/extensions/common/api/declarative_net_request/test_utils.cc
@@ -184,6 +184,8 @@
     bool has_background_script) {
   std::vector<std::string> permissions = hosts;
   permissions.push_back(kAPIPermission);
+  permissions.push_back("webRequest");
+  permissions.push_back("webRequestBlocking");
 
   std::vector<std::string> background_scripts;
   if (has_background_script)
diff --git a/fuchsia/OWNERS b/fuchsia/OWNERS
index e7034ea..205c2d5 100644
--- a/fuchsia/OWNERS
+++ b/fuchsia/OWNERS
@@ -1 +1,5 @@
 file://build/fuchsia/OWNERS
+
+# COMPONENT: Fuchsia
+# OS: Fuchsia
+# TEAM: cr-fuchsia@chromium.org
diff --git a/gpu/command_buffer/client/context_support.h b/gpu/command_buffer/client/context_support.h
index 3da9d4a..f6b7ab2 100644
--- a/gpu/command_buffer/client/context_support.h
+++ b/gpu/command_buffer/client/context_support.h
@@ -135,6 +135,12 @@
 
   virtual unsigned int GetTransferBufferFreeSize() const = 0;
 
+  // Determines if hardware decode acceleration is supported for JPEG images.
+  virtual bool IsJpegDecodeAccelerationSupported() const = 0;
+
+  // Determines if hardware decode acceleration is supported for WebP images.
+  virtual bool IsWebPDecodeAccelerationSupported() const = 0;
+
   // Determines if an encoded image can be decoded using hardware decode
   // acceleration. If this method returns true, then the client can be confident
   // that a call to RasterInterface::ScheduleImageDecode() will succeed.
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 2881941..0bc9f30 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -6718,6 +6718,16 @@
   return 0;
 }
 
+bool GLES2Implementation::IsJpegDecodeAccelerationSupported() const {
+  NOTREACHED();
+  return false;
+}
+
+bool GLES2Implementation::IsWebPDecodeAccelerationSupported() const {
+  NOTREACHED();
+  return false;
+}
+
 bool GLES2Implementation::CanDecodeWithHardwareAcceleration(
     base::span<const uint8_t> encoded_data) const {
   NOTREACHED();
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index 0f31140..6359d34a 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -143,6 +143,8 @@
       const std::vector<std::pair<uint32_t, uint32_t>>& entries) override;
   void DeleteTransferCacheEntry(uint32_t type, uint32_t id) override;
   unsigned int GetTransferBufferFreeSize() const override;
+  bool IsJpegDecodeAccelerationSupported() const override;
+  bool IsWebPDecodeAccelerationSupported() const override;
   bool CanDecodeWithHardwareAcceleration(
       base::span<const uint8_t> encoded_data) const override;
 
diff --git a/gpu/command_buffer/client/image_decode_accelerator_interface.h b/gpu/command_buffer/client/image_decode_accelerator_interface.h
index d56c6b6c..1a94e0ed 100644
--- a/gpu/command_buffer/client/image_decode_accelerator_interface.h
+++ b/gpu/command_buffer/client/image_decode_accelerator_interface.h
@@ -27,6 +27,10 @@
   virtual bool IsImageSupported(
       base::span<const uint8_t> encoded_data) const = 0;
 
+  virtual bool IsJpegDecodeAccelerationSupported() const = 0;
+
+  virtual bool IsWebPDecodeAccelerationSupported() const = 0;
+
   virtual SyncToken ScheduleImageDecode(
       base::span<const uint8_t> encoded_data,
       const gfx::Size& output_size,
diff --git a/gpu/command_buffer/client/raster_implementation.cc b/gpu/command_buffer/client/raster_implementation.cc
index 407fbdf..3540d078 100644
--- a/gpu/command_buffer/client/raster_implementation.cc
+++ b/gpu/command_buffer/client/raster_implementation.cc
@@ -543,9 +543,20 @@
   return transfer_buffer_->GetFreeSize();
 }
 
+bool RasterImplementation::IsJpegDecodeAccelerationSupported() const {
+  return image_decode_accelerator_ &&
+         image_decode_accelerator_->IsJpegDecodeAccelerationSupported();
+}
+
+bool RasterImplementation::IsWebPDecodeAccelerationSupported() const {
+  return image_decode_accelerator_ &&
+         image_decode_accelerator_->IsWebPDecodeAccelerationSupported();
+}
+
 bool RasterImplementation::CanDecodeWithHardwareAcceleration(
     base::span<const uint8_t> encoded_data) const {
-  return image_decode_accelerator_->IsImageSupported(encoded_data);
+  return image_decode_accelerator_ &&
+         image_decode_accelerator_->IsImageSupported(encoded_data);
 }
 
 const std::string& RasterImplementation::GetLogPrefix() const {
diff --git a/gpu/command_buffer/client/raster_implementation.h b/gpu/command_buffer/client/raster_implementation.h
index 3af07f2..0825a9a 100644
--- a/gpu/command_buffer/client/raster_implementation.h
+++ b/gpu/command_buffer/client/raster_implementation.h
@@ -183,6 +183,8 @@
       const std::vector<std::pair<uint32_t, uint32_t>>& entries) override;
   void DeleteTransferCacheEntry(uint32_t type, uint32_t id) override;
   unsigned int GetTransferBufferFreeSize() const override;
+  bool IsJpegDecodeAccelerationSupported() const override;
+  bool IsWebPDecodeAccelerationSupported() const override;
   bool CanDecodeWithHardwareAcceleration(
       base::span<const uint8_t> encoded_data) const override;
 
diff --git a/gpu/command_buffer/client/raster_implementation_gles_unittest.cc b/gpu/command_buffer/client/raster_implementation_gles_unittest.cc
index 633d53d..f191b0a4 100644
--- a/gpu/command_buffer/client/raster_implementation_gles_unittest.cc
+++ b/gpu/command_buffer/client/raster_implementation_gles_unittest.cc
@@ -226,6 +226,8 @@
       const std::vector<std::pair<uint32_t, uint32_t>>& entries) override {}
   void DeleteTransferCacheEntry(uint32_t type, uint32_t id) override {}
   unsigned int GetTransferBufferFreeSize() const override { return 0; }
+  bool IsJpegDecodeAccelerationSupported() const override { return false; }
+  bool IsWebPDecodeAccelerationSupported() const override { return false; }
   bool CanDecodeWithHardwareAcceleration(
       base::span<const uint8_t> encoded_data) const override {
     return false;
diff --git a/gpu/command_buffer/client/webgpu_implementation.cc b/gpu/command_buffer/client/webgpu_implementation.cc
index b50308c..f8c86a5 100644
--- a/gpu/command_buffer/client/webgpu_implementation.cc
+++ b/gpu/command_buffer/client/webgpu_implementation.cc
@@ -153,6 +153,14 @@
   NOTREACHED();
   return 0;
 }
+bool WebGPUImplementation::IsJpegDecodeAccelerationSupported() const {
+  NOTREACHED();
+  return false;
+}
+bool WebGPUImplementation::IsWebPDecodeAccelerationSupported() const {
+  NOTREACHED();
+  return false;
+}
 bool WebGPUImplementation::CanDecodeWithHardwareAcceleration(
     base::span<const uint8_t> encoded_data) const {
   NOTREACHED();
diff --git a/gpu/command_buffer/client/webgpu_implementation.h b/gpu/command_buffer/client/webgpu_implementation.h
index 744c2045..4c56924 100644
--- a/gpu/command_buffer/client/webgpu_implementation.h
+++ b/gpu/command_buffer/client/webgpu_implementation.h
@@ -83,6 +83,8 @@
       const std::vector<std::pair<uint32_t, uint32_t>>& entries) override;
   void DeleteTransferCacheEntry(uint32_t type, uint32_t id) override;
   unsigned int GetTransferBufferFreeSize() const override;
+  bool IsJpegDecodeAccelerationSupported() const override;
+  bool IsWebPDecodeAccelerationSupported() const override;
   bool CanDecodeWithHardwareAcceleration(
       base::span<const uint8_t> encoded_data) const override;
 
diff --git a/gpu/ipc/client/image_decode_accelerator_proxy.cc b/gpu/ipc/client/image_decode_accelerator_proxy.cc
index 7765f6ef..cfb5143 100644
--- a/gpu/ipc/client/image_decode_accelerator_proxy.cc
+++ b/gpu/ipc/client/image_decode_accelerator_proxy.cc
@@ -191,6 +191,26 @@
   return false;
 }
 
+bool ImageDecodeAcceleratorProxy::IsJpegDecodeAccelerationSupported() const {
+  const auto& profiles =
+      host_->gpu_info().image_decode_accelerator_supported_profiles;
+  for (const auto& profile : profiles) {
+    if (profile.image_type == ImageDecodeAcceleratorType::kJpeg)
+      return true;
+  }
+  return false;
+}
+
+bool ImageDecodeAcceleratorProxy::IsWebPDecodeAccelerationSupported() const {
+  const auto& profiles =
+      host_->gpu_info().image_decode_accelerator_supported_profiles;
+  for (const auto& profile : profiles) {
+    if (profile.image_type == ImageDecodeAcceleratorType::kWebP)
+      return true;
+  }
+  return false;
+}
+
 SyncToken ImageDecodeAcceleratorProxy::ScheduleImageDecode(
     base::span<const uint8_t> encoded_data,
     const gfx::Size& output_size,
diff --git a/gpu/ipc/client/image_decode_accelerator_proxy.h b/gpu/ipc/client/image_decode_accelerator_proxy.h
index b40a3fe..38d021e 100644
--- a/gpu/ipc/client/image_decode_accelerator_proxy.h
+++ b/gpu/ipc/client/image_decode_accelerator_proxy.h
@@ -56,6 +56,12 @@
   // teardown if the decode fails.
   bool IsImageSupported(base::span<const uint8_t> encoded_data) const override;
 
+  // Determines if hardware decode acceleration is supported for JPEG images.
+  bool IsJpegDecodeAccelerationSupported() const override;
+
+  // Determines if hardware decode acceleration is supported for WebP images.
+  bool IsWebPDecodeAccelerationSupported() const override;
+
   // Schedules a hardware-accelerated image decode on the GPU process. The image
   // in |encoded_data| is decoded and scaled to |output_size|. Upon completion
   // and after the sync token corresponding to
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index b819160..12478c3 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -1791,7 +1791,7 @@
 
     builders {
       name: "linux-ozone-rel"
-      mixins: "linux-ci"
+      mixins: "linux-ci-goma-rbe-prod"
       mixins: "builderless"
     }
 
@@ -4491,6 +4491,7 @@
     builders {
       mixins: "builderless"
       mixins: "linux-try"
+      mixins: "goma-rbe-prod"
       name: "linux-ozone-rel"
       mixins: "builderless"
     }
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index b9b1a25d..fbbb0cd 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -3094,6 +3094,11 @@
     short_name: "gpu"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/linux-ozone-rel"
+    category: "week3a|linux"
+    short_name: "ozone"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/linux-annotator-rel"
     category: "week3a|linux"
     short_name: "anno"
diff --git a/ios/build/bots/scripts/xcode_log_parser.py b/ios/build/bots/scripts/xcode_log_parser.py
index 43b1245..0071e09 100644
--- a/ios/build/bots/scripts/xcode_log_parser.py
+++ b/ios/build/bots/scripts/xcode_log_parser.py
@@ -183,7 +183,7 @@
 
   @staticmethod
   def collect_test_results(xcresult, output):
-    """Gets test result data from xcresult.
+    """Gets test result and diagnostic data from xcresult.
 
     Args:
       xcresult: (str) A path to xcresult.
@@ -224,6 +224,7 @@
     else:
       test_results['failed'] = Xcode11LogParser._list_of_failed_tests(root)
       test_results['passed'] = Xcode11LogParser._list_of_passed_tests(xcresult)
+    Xcode11LogParser._export_diagnostic_data(xcresult + '.xcresult')
     return test_results
 
   @staticmethod
@@ -250,6 +251,34 @@
       copy_screenshots_for_failed_test(failure_summary['message']['_value'],
                                        test_case_folder)
 
+  @staticmethod
+  def _export_diagnostic_data(xcresult):
+    """Exports diagnostic data from xcresult to xcresult_diagnostic folder.
+
+    Since Xcode 11 format of result bundles changed, to get diagnostic data
+    need to run command below:
+    xcresulttool export --type directory --id DIAGNOSTICS_REF --output-path
+    ./export_folder --path ./RB.xcresult
+
+    Args:
+      xcresult: (str) A path to xcresult directory.
+    """
+    plist_path = os.path.join(xcresult, 'Info.plist')
+    if not (os.path.exists(xcresult) and os.path.exists(plist_path)):
+      return
+    root = json.loads(Xcode11LogParser._xcresulttool_get(xcresult))
+    try:
+      diagnostics_ref = root['actions']['_values'][0]['actionResult'][
+          'diagnosticsRef']['id']['_value']
+      export_command = ['xcresulttool', 'export',
+                        '--type', 'directory',
+                        '--id', diagnostics_ref,
+                        '--path', xcresult,
+                        '--output-path', '%s_diagnostic' % xcresult]
+      subprocess.check_output(export_command).strip()
+    except KeyError:
+      LOGGER.warn('Did not parse diagnosticsRef from %s!' % xcresult)
+
 
 class XcodeLogParser(object):
   """Xcode log parser. Parses logs for Xcode until version 11."""
diff --git a/ios/chrome/browser/overlays/overlay_presenter_impl.h b/ios/chrome/browser/overlays/overlay_presenter_impl.h
index d6e095c6..a56b4ce 100644
--- a/ios/chrome/browser/overlays/overlay_presenter_impl.h
+++ b/ios/chrome/browser/overlays/overlay_presenter_impl.h
@@ -112,10 +112,11 @@
                               OverlayRequest* request) override;
 
   // OverlayPresentationContextObserver:
-  void OverlayPresentationContextWillChangeActivationState(
+  void OverlayPresentationContextWillChangePresentationCapabilities(
       OverlayPresentationContext* presentation_context,
-      bool activating) override;
-  void OverlayPresentationContextDidChangeActivationState(
+      OverlayPresentationContext::UIPresentationCapabilities capabilities)
+      override;
+  void OverlayPresentationContextDidChangePresentationCapabilities(
       OverlayPresentationContext* presentation_context) override;
 
   // WebStateListObserver:
diff --git a/ios/chrome/browser/overlays/overlay_presenter_impl.mm b/ios/chrome/browser/overlays/overlay_presenter_impl.mm
index af8d418..b6a9461 100644
--- a/ios/chrome/browser/overlays/overlay_presenter_impl.mm
+++ b/ios/chrome/browser/overlays/overlay_presenter_impl.mm
@@ -187,13 +187,14 @@
   // Overlays cannot be presented if one is already presented.
   DCHECK(!presenting_);
 
-  // Overlays cannot be shown without an active presentation context.
-  if (!presentation_context_ || !presentation_context_->IsActive())
+  // Overlays cannot be shown without a presentation context.
+  if (!presentation_context_)
     return;
 
-  // No presentation is necessary if there is no active reqeust.
+  // No presentation is necessary if there is no active reqeust or the context
+  // is unable to show it.
   OverlayRequest* request = GetActiveRequest();
-  if (!request)
+  if (!request || !presentation_context_->CanShowUIForRequest(request))
     return;
 
   presenting_ = true;
@@ -313,21 +314,25 @@
 
 #pragma mark - OverlayPresentationContextObserver
 
-void OverlayPresenterImpl::OverlayPresentationContextWillChangeActivationState(
-    OverlayPresentationContext* presentation_context,
-    bool activating) {
+void OverlayPresenterImpl::
+    OverlayPresentationContextWillChangePresentationCapabilities(
+        OverlayPresentationContext* presentation_context,
+        OverlayPresentationContext::UIPresentationCapabilities capabilities) {
   DCHECK_EQ(presentation_context_, presentation_context);
-  // Hide the presented overlay UI if the presentation context is deactivating.
-  if (!activating && presenting_)
+  // Hide the presented overlay UI if the presentation context is transitioning
+  // to a state where that UI is not supported.
+  OverlayRequest* request = GetActiveRequest();
+  if (presenting_ &&
+      !presentation_context->CanShowUIForRequest(request, capabilities)) {
     presentation_context_->HideOverlayUI(this, GetActiveRequest());
+  }
 }
 
-void OverlayPresenterImpl::OverlayPresentationContextDidChangeActivationState(
-    OverlayPresentationContext* presentation_context) {
+void OverlayPresenterImpl::
+    OverlayPresentationContextDidChangePresentationCapabilities(
+        OverlayPresentationContext* presentation_context) {
   DCHECK_EQ(presentation_context_, presentation_context);
-  // Attempt to present the active request's overlay UI if the context is being
-  // activated.
-  if (presentation_context_->IsActive())
+  if (!presenting_)
     PresentOverlayForActiveRequest();
 }
 
diff --git a/ios/chrome/browser/overlays/overlay_presenter_impl_unittest.mm b/ios/chrome/browser/overlays/overlay_presenter_impl_unittest.mm
index ea68af1..6d1bafb 100644
--- a/ios/chrome/browser/overlays/overlay_presenter_impl_unittest.mm
+++ b/ios/chrome/browser/overlays/overlay_presenter_impl_unittest.mm
@@ -148,7 +148,8 @@
 // activated.
 TEST_F(OverlayPresenterImplTest, PresentAfterContextActivation) {
   // Add a WebState to the list and add a request to that WebState's queue.
-  presentation_context().SetIsActive(false);
+  presentation_context().SetPresentationCapabilities(
+      OverlayPresentationContext::UIPresentationCapabilities::kNone);
   presenter().SetPresentationContext(&presentation_context());
   web_state_list().InsertWebState(
       /*index=*/0, std::make_unique<web::TestWebState>(),
@@ -158,7 +159,8 @@
             presentation_context().GetPresentationState(request));
 
   // Activate the presentation context and verify that the UI is presented.
-  presentation_context().SetIsActive(true);
+  presentation_context().SetPresentationCapabilities(
+      OverlayPresentationContext::UIPresentationCapabilities::kPresented);
   EXPECT_EQ(FakeOverlayPresentationContext::PresentationState::kPresented,
             presentation_context().GetPresentationState(request));
   EXPECT_TRUE(presenter().IsShowingOverlayUI());
@@ -178,7 +180,8 @@
   ASSERT_TRUE(presenter().IsShowingOverlayUI());
 
   // Deactivate the presentation context and verify that the UI is hidden.
-  presentation_context().SetIsActive(false);
+  presentation_context().SetPresentationCapabilities(
+      OverlayPresentationContext::UIPresentationCapabilities::kNone);
   EXPECT_EQ(FakeOverlayPresentationContext::PresentationState::kHidden,
             presentation_context().GetPresentationState(request));
   EXPECT_FALSE(presenter().IsShowingOverlayUI());
diff --git a/ios/chrome/browser/overlays/public/overlay_presentation_context.h b/ios/chrome/browser/overlays/public/overlay_presentation_context.h
index f6342b4..8818e7e 100644
--- a/ios/chrome/browser/overlays/public/overlay_presentation_context.h
+++ b/ios/chrome/browser/overlays/public/overlay_presentation_context.h
@@ -22,9 +22,32 @@
   virtual void AddObserver(OverlayPresentationContextObserver* observer) = 0;
   virtual void RemoveObserver(OverlayPresentationContextObserver* observer) = 0;
 
-  // Whether the presentation context is active.  Overlay UI will only be
-  // presented for active contexts.
-  virtual bool IsActive() const = 0;
+  // Enum describing the current capabilities of the presentation context.
+  enum UIPresentationCapabilities {
+    // The context cannot show any overlay UI.
+    kNone = 0,
+    // The context can show overlay UI that is contained as a child to its
+    // backing UIViewController.
+    kContained = 1 << 0,
+    // The context can show overlay UI that is presented upon its backing
+    // UIViewController.
+    kPresented = 1 << 1,
+  };
+
+  // Returns the context's current presentation capabilities.  Overlay UI should
+  // not be shown in this context if CanShowUIForRequest() returns false for
+  // the current capabilities.
+  virtual UIPresentationCapabilities GetPresentationCapabilities() const = 0;
+
+  // Returns whether the presentation context can show the UI for |request|
+  // while it has |capabilities|.
+  virtual bool CanShowUIForRequest(
+      OverlayRequest* request,
+      UIPresentationCapabilities capabilities) const = 0;
+
+  // Returns whether the presentation context supports showing the UI for
+  // |request| with its current presentation capabilities.
+  virtual bool CanShowUIForRequest(OverlayRequest* request) const = 0;
 
   // Called by |presenter| to show the overlay UI for |request|.
   // |presentation_callback| must be called when the UI is finished being
diff --git a/ios/chrome/browser/overlays/public/overlay_presentation_context_observer.h b/ios/chrome/browser/overlays/public/overlay_presentation_context_observer.h
index facfa0a..7023d92 100644
--- a/ios/chrome/browser/overlays/public/overlay_presentation_context_observer.h
+++ b/ios/chrome/browser/overlays/public/overlay_presentation_context_observer.h
@@ -6,8 +6,7 @@
 #define IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_OVERLAY_PRESENTATION_CONTEXT_OBSERVER_H_
 
 #include "base/observer_list_types.h"
-
-class OverlayPresentationContext;
+#import "ios/chrome/browser/overlays/public/overlay_presentation_context.h"
 
 // Observer class for the ObserverPresentationContext.
 class OverlayPresentationContextObserver : public base::CheckedObserver {
@@ -16,12 +15,12 @@
 
   // Called before |presentation_context|'s activation state changes to
   // |activating|.
-  virtual void OverlayPresentationContextWillChangeActivationState(
+  virtual void OverlayPresentationContextWillChangePresentationCapabilities(
       OverlayPresentationContext* presentation_context,
-      bool activating) {}
+      OverlayPresentationContext::UIPresentationCapabilities capabilities) {}
 
   // Called after |presentation_context|'s activation state changes.
-  virtual void OverlayPresentationContextDidChangeActivationState(
+  virtual void OverlayPresentationContextDidChangePresentationCapabilities(
       OverlayPresentationContext* presentation_context) {}
 };
 
diff --git a/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.cc b/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.cc
index 550f77d..c2ae57e8 100644
--- a/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.cc
+++ b/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.cc
@@ -36,16 +36,18 @@
   std::move(state.dismissal_callback).Run(reason);
 }
 
-void FakeOverlayPresentationContext::SetIsActive(bool active) {
-  if (active_ == active)
+void FakeOverlayPresentationContext::SetPresentationCapabilities(
+    UIPresentationCapabilities capabilities) {
+  if (capabilities_ == capabilities)
     return;
 
   for (auto& observer : observers_) {
-    observer.OverlayPresentationContextWillChangeActivationState(this, active);
+    observer.OverlayPresentationContextWillChangePresentationCapabilities(
+        this, capabilities);
   }
-  active_ = active;
+  capabilities_ = capabilities;
   for (auto& observer : observers_) {
-    observer.OverlayPresentationContextDidChangeActivationState(this);
+    observer.OverlayPresentationContextDidChangePresentationCapabilities(this);
   }
 }
 
@@ -59,8 +61,21 @@
   observers_.RemoveObserver(observer);
 }
 
-bool FakeOverlayPresentationContext::IsActive() const {
-  return active_;
+OverlayPresentationContext::UIPresentationCapabilities
+FakeOverlayPresentationContext::GetPresentationCapabilities() const {
+  return capabilities_;
+}
+
+bool FakeOverlayPresentationContext::CanShowUIForRequest(
+    OverlayRequest* request,
+    UIPresentationCapabilities capabilities) const {
+  return capabilities !=
+         OverlayPresentationContext::UIPresentationCapabilities::kNone;
+}
+
+bool FakeOverlayPresentationContext::CanShowUIForRequest(
+    OverlayRequest* request) const {
+  return CanShowUIForRequest(request, capabilities_);
 }
 
 void FakeOverlayPresentationContext::ShowOverlayUI(
diff --git a/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.h b/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.h
index 0806f99..d6dd7770 100644
--- a/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.h
+++ b/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.h
@@ -37,13 +37,16 @@
   void SimulateDismissalForRequest(OverlayRequest* request,
                                    OverlayDismissalReason reason);
 
-  // Setter for whether the context is active.
-  void SetIsActive(bool active);
+  void SetPresentationCapabilities(UIPresentationCapabilities capabilities);
 
   // OverlayUIDelegate:
   void AddObserver(OverlayPresentationContextObserver* observer) override;
   void RemoveObserver(OverlayPresentationContextObserver* observer) override;
-  bool IsActive() const override;
+  UIPresentationCapabilities GetPresentationCapabilities() const override;
+  bool CanShowUIForRequest(
+      OverlayRequest* request,
+      UIPresentationCapabilities capabilities) const override;
+  bool CanShowUIForRequest(OverlayRequest* request) const override;
   void ShowOverlayUI(OverlayPresenter* presenter,
                      OverlayRequest* request,
                      OverlayPresentationCallback presentation_callback,
@@ -66,8 +69,11 @@
 
   // The UI states for each request.
   std::map<OverlayRequest*, FakeUIState> states_;
-  // Whether the context is active.
-  bool active_ = true;
+
+  UIPresentationCapabilities capabilities_ =
+      static_cast<UIPresentationCapabilities>(
+          UIPresentationCapabilities::kContained |
+          UIPresentationCapabilities::kPresented);
 
   base::ObserverList<OverlayPresentationContextObserver,
                      /* check_empty= */ true>
diff --git a/ios/chrome/browser/payments/ios_payment_instrument.h b/ios/chrome/browser/payments/ios_payment_instrument.h
index b757473..b5efa913 100644
--- a/ios/chrome/browser/payments/ios_payment_instrument.h
+++ b/ios/chrome/browser/payments/ios_payment_instrument.h
@@ -68,6 +68,10 @@
   void IsValidForPaymentMethodIdentifier(
       const std::string& payment_method_identifier,
       bool* is_valid) const override;
+  bool HandlesShippingAddress() const override;
+  bool HandlesPayerName() const override;
+  bool HandlesPayerEmail() const override;
+  bool HandlesPayerPhone() const override;
   base::WeakPtr<PaymentInstrument> AsWeakPtr() override;
 
   // Given that the icon for the iOS payment instrument can only be determined
diff --git a/ios/chrome/browser/payments/ios_payment_instrument.mm b/ios/chrome/browser/payments/ios_payment_instrument.mm
index e4325f88..139bd1f 100644
--- a/ios/chrome/browser/payments/ios_payment_instrument.mm
+++ b/ios/chrome/browser/payments/ios_payment_instrument.mm
@@ -118,6 +118,22 @@
   *is_valid = method_name_ == payment_method_identifier;
 }
 
+bool IOSPaymentInstrument::HandlesShippingAddress() const {
+  return false;
+}
+
+bool IOSPaymentInstrument::HandlesPayerName() const {
+  return false;
+}
+
+bool IOSPaymentInstrument::HandlesPayerEmail() const {
+  return false;
+}
+
+bool IOSPaymentInstrument::HandlesPayerPhone() const {
+  return false;
+}
+
 base::WeakPtr<PaymentInstrument> IOSPaymentInstrument::AsWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
 }
diff --git a/ios/chrome/browser/ui/overlays/overlay_container_coordinator.mm b/ios/chrome/browser/ui/overlays/overlay_container_coordinator.mm
index b280aaa..e46ccf1 100644
--- a/ios/chrome/browser/ui/overlays/overlay_container_coordinator.mm
+++ b/ios/chrome/browser/ui/overlays/overlay_container_coordinator.mm
@@ -21,8 +21,10 @@
     OverlayContainerViewControllerDelegate>
 // Whether the coordinator is started.
 @property(nonatomic, assign, getter=isStarted) BOOL started;
-// The UI delegate that is used to drive presentation for this container.
-@property(nonatomic, readonly) OverlayPresentationContextImpl* UIDelegate;
+// The presentation context used by OverlayPresenter to drive presentation for
+// this container.
+@property(nonatomic, readonly)
+    OverlayPresentationContextImpl* presentationContext;
 @end
 
 @implementation OverlayContainerCoordinator
@@ -34,10 +36,10 @@
                                        browser:browser]) {
     OverlayPresentationContextImpl::Container::CreateForUserData(browser,
                                                                  browser);
-    _UIDelegate =
+    _presentationContext =
         OverlayPresentationContextImpl::Container::FromUserData(browser)
             ->PresentationContextForModality(modality);
-    DCHECK(_UIDelegate);
+    DCHECK(_presentationContext);
   }
   return self;
 }
@@ -61,13 +63,14 @@
   [self.baseViewController.view addSubview:containerView];
   AddSameConstraints(containerView, self.baseViewController.view);
   [_viewController didMoveToParentViewController:self.baseViewController];
+  self.presentationContext->SetCoordinator(self);
 }
 
 - (void)stop {
   if (!self.started)
     return;
   self.started = NO;
-  self.UIDelegate->SetCoordinator(nil);
+  self.presentationContext->SetCoordinator(nil);
   // Remove the container view and reset the view controller.
   [_viewController willMoveToParentViewController:nil];
   [_viewController.view removeFromSuperview];
@@ -80,10 +83,7 @@
 - (void)containerViewController:
             (OverlayContainerViewController*)containerViewController
                 didMoveToWindow:(UIWindow*)window {
-  // UIViewController presentation no-ops when attempted on window-less parent
-  // view controllers.  Wait to set UI delegate's coordinator until the
-  // container is added to a window.
-  self.UIDelegate->SetCoordinator(window ? self : nil);
+  self.presentationContext->WindowDidChange();
 }
 
 @end
diff --git a/ios/chrome/browser/ui/overlays/overlay_coordinator_factory.h b/ios/chrome/browser/ui/overlays/overlay_coordinator_factory.h
index 9cb45b2..60bc484 100644
--- a/ios/chrome/browser/ui/overlays/overlay_coordinator_factory.h
+++ b/ios/chrome/browser/ui/overlays/overlay_coordinator_factory.h
@@ -26,6 +26,11 @@
 // |+factoryForBrowser:modality:|.
 - (instancetype)init NS_UNAVAILABLE;
 
+// Returns whether the OverlayRequestCoordinator subclass responsible for
+// showing |request|'s overlay UI uses a child UIViewController instead of a
+// presented UIViewController.
+- (BOOL)coordinatorForRequestUsesChildViewController:(OverlayRequest*)request;
+
 // Creates a coordinator to show |request|'s overlay UI.
 - (OverlayRequestCoordinator*)
     newCoordinatorForRequest:(OverlayRequest*)request
diff --git a/ios/chrome/browser/ui/overlays/overlay_coordinator_factory.mm b/ios/chrome/browser/ui/overlays/overlay_coordinator_factory.mm
index f44c089..c01ff353 100644
--- a/ios/chrome/browser/ui/overlays/overlay_coordinator_factory.mm
+++ b/ios/chrome/browser/ui/overlays/overlay_coordinator_factory.mm
@@ -38,19 +38,32 @@
       supportedOverlayRequestCoordinatorClasses:supportedCoordinatorClasses];
 }
 
+- (BOOL)coordinatorForRequestUsesChildViewController:(OverlayRequest*)request {
+  return [[self coordinatorClassForRequest:request]
+      showsOverlayUsingChildViewController];
+}
+
 - (OverlayRequestCoordinator*)
     newCoordinatorForRequest:(OverlayRequest*)request
                     delegate:(OverlayRequestCoordinatorDelegate*)delegate
           baseViewController:(UIViewController*)baseViewController {
+  return [[[self coordinatorClassForRequest:request] alloc]
+      initWithBaseViewController:baseViewController
+                         browser:self.browser
+                         request:request
+                        delegate:delegate];
+}
+
+#pragma mark - Helpers
+
+// Returns the OverlayRequestCoordinator subclass responsible for showing
+// |request|'s overlay UI.
+- (Class)coordinatorClassForRequest:(OverlayRequest*)request {
   NSArray<Class>* supportedClasses =
       self.supportedOverlayRequestCoordinatorClasses;
   for (Class coordinatorClass in supportedClasses) {
     if ([coordinatorClass supportsRequest:request]) {
-      return [[coordinatorClass alloc]
-          initWithBaseViewController:baseViewController
-                             browser:self.browser
-                             request:request
-                            delegate:delegate];
+      return coordinatorClass;
     }
   }
   NOTREACHED() << "Received unsupported request type.";
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h
index 73f45ba..48c5eea 100644
--- a/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h
+++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h
@@ -51,15 +51,22 @@
   };
 
   // The OverlayContainerCoordinator is used to present the overlay UI at the
-  // correct modality in the app.  Should only be set when the coordinator's
-  // presentation context is able to present.
+  // correct modality in the app.  Should only be set when the coordinator is
+  // started.
   OverlayContainerCoordinator* coordinator() const { return coordinator_; }
   void SetCoordinator(OverlayContainerCoordinator* coordinator);
 
+  // Called when |coordinator_|'s view was moved to a new window.
+  void WindowDidChange();
+
   // OverlayPresentationContext:
   void AddObserver(OverlayPresentationContextObserver* observer) override;
   void RemoveObserver(OverlayPresentationContextObserver* observer) override;
-  bool IsActive() const override;
+  UIPresentationCapabilities GetPresentationCapabilities() const override;
+  bool CanShowUIForRequest(
+      OverlayRequest* request,
+      UIPresentationCapabilities capabilities) const override;
+  bool CanShowUIForRequest(OverlayRequest* request) const override;
   void ShowOverlayUI(OverlayPresenter* presenter,
                      OverlayRequest* request,
                      OverlayPresentationCallback presentation_callback,
@@ -79,6 +86,10 @@
   // Returns the UI state for |request|.
   OverlayRequestUIState* GetRequestUIState(OverlayRequest* request);
 
+  // Updates |coordinator_| and |presentation_capabilities_| using
+  // |coordinator|.
+  void UpdateForCoordinator(OverlayContainerCoordinator* coordinator);
+
   // Shows the UI for the presented request using the container coordinator.
   void ShowUIForPresentedRequest();
 
@@ -133,6 +144,9 @@
   OverlayRequestCoordinatorFactory* coordinator_factory_ = nil;
   // The coordinator responsible for presenting the UI delegate's UI.
   OverlayContainerCoordinator* coordinator_ = nil;
+  // The presentation capabilities of |coordinator_|'s view controller.
+  UIPresentationCapabilities presentation_capabilities_ =
+      UIPresentationCapabilities::kNone;
   // The request that is currently presented by |presenter_|.  The UI for this
   // request might not yet be visible if no OverlayContainerCoordinator has been
   // provided.  When a new request is presented, the UI state for the request
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.mm b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.mm
index 29aeabae..fde3192 100644
--- a/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.mm
+++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.mm
@@ -4,6 +4,8 @@
 
 #import "ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h"
 
+#import <UIKit/UIKit.h>
+
 #include "base/bind.h"
 #include "base/callback.h"
 #import "ios/chrome/browser/main/browser.h"
@@ -64,19 +66,14 @@
   if (coordinator_ == coordinator)
     return;
 
-  for (auto& observer : observers_) {
-    observer.OverlayPresentationContextWillChangeActivationState(this,
-                                                                 !!coordinator);
-  }
-
-  coordinator_ = coordinator;
+  UpdateForCoordinator(coordinator);
 
   // The new coordinator should be started before provided to the UI delegate.
   DCHECK(!coordinator_ || coordinator_.viewController);
+}
 
-  for (auto& observer : observers_) {
-    observer.OverlayPresentationContextDidChangeActivationState(this);
-  }
+void OverlayPresentationContextImpl::WindowDidChange() {
+  UpdateForCoordinator(coordinator_);
 }
 
 #pragma mark OverlayPresentationContext
@@ -91,8 +88,25 @@
   observers_.RemoveObserver(observer);
 }
 
-bool OverlayPresentationContextImpl::IsActive() const {
-  return !!coordinator_;
+OverlayPresentationContext::UIPresentationCapabilities
+OverlayPresentationContextImpl::GetPresentationCapabilities() const {
+  return presentation_capabilities_;
+}
+
+bool OverlayPresentationContextImpl::CanShowUIForRequest(
+    OverlayRequest* request,
+    UIPresentationCapabilities capabilities) const {
+  BOOL uses_child_view_controller = [coordinator_factory_
+      coordinatorForRequestUsesChildViewController:request];
+  UIPresentationCapabilities required_capability =
+      uses_child_view_controller ? UIPresentationCapabilities::kContained
+                                 : UIPresentationCapabilities::kPresented;
+  return !!(capabilities & required_capability);
+}
+
+bool OverlayPresentationContextImpl::CanShowUIForRequest(
+    OverlayRequest* request) const {
+  return CanShowUIForRequest(request, GetPresentationCapabilities());
 }
 
 void OverlayPresentationContextImpl::ShowOverlayUI(
@@ -195,6 +209,40 @@
   return request ? states_[request].get() : nullptr;
 }
 
+void OverlayPresentationContextImpl::UpdateForCoordinator(
+    OverlayContainerCoordinator* coordinator) {
+  UIPresentationCapabilities capabilities = UIPresentationCapabilities::kNone;
+  UIViewController* view_controller = coordinator.viewController;
+  // Any UIViewController can contain overlay UI as a child.
+  if (view_controller) {
+    capabilities = static_cast<UIPresentationCapabilities>(
+        capabilities | UIPresentationCapabilities::kContained);
+  }
+  // Only UIViewControllers attached to a window can present overlay UI.
+  if (view_controller.view.window) {
+    capabilities = static_cast<UIPresentationCapabilities>(
+        capabilities | UIPresentationCapabilities::kPresented);
+  }
+  bool capabilities_changed = presentation_capabilities_ != capabilities;
+
+  if (capabilities_changed) {
+    for (auto& observer : observers_) {
+      observer.OverlayPresentationContextWillChangePresentationCapabilities(
+          this, capabilities);
+    }
+  }
+
+  presentation_capabilities_ = capabilities;
+  coordinator_ = coordinator;
+
+  if (capabilities_changed) {
+    for (auto& observer : observers_) {
+      observer.OverlayPresentationContextDidChangePresentationCapabilities(
+          this);
+    }
+  }
+}
+
 #pragma mark Presentation and Dismissal helpers
 
 void OverlayPresentationContextImpl::ShowUIForPresentedRequest() {
diff --git a/ios/chrome/browser/ui/overlays/overlay_request_coordinator.h b/ios/chrome/browser/ui/overlays/overlay_request_coordinator.h
index 180e195..0799cb5 100644
--- a/ios/chrome/browser/ui/overlays/overlay_request_coordinator.h
+++ b/ios/chrome/browser/ui/overlays/overlay_request_coordinator.h
@@ -16,6 +16,10 @@
 // Returns whether this overlay coordinator type supports |request|.
 + (BOOL)supportsRequest:(OverlayRequest*)request;
 
+// Returns whether this overlay coordinator type uses child view controllers
+// instead of presentating over the container context.  Default value is NO.
+@property(class, nonatomic, readonly) BOOL showsOverlayUsingChildViewController;
+
 // Initializer for a coordinator for |request|.
 - (instancetype)initWithBaseViewController:(UIViewController*)viewController
                                    browser:(Browser*)browser
diff --git a/ios/chrome/browser/ui/overlays/overlay_request_coordinator.mm b/ios/chrome/browser/ui/overlays/overlay_request_coordinator.mm
index fdcd07b..39d5a3d4 100644
--- a/ios/chrome/browser/ui/overlays/overlay_request_coordinator.mm
+++ b/ios/chrome/browser/ui/overlays/overlay_request_coordinator.mm
@@ -17,6 +17,10 @@
   return NO;
 }
 
++ (BOOL)showsOverlayUsingChildViewController {
+  return NO;
+}
+
 - (instancetype)initWithBaseViewController:(UIViewController*)viewController
                                    browser:(Browser*)browser
                                    request:(OverlayRequest*)request
diff --git a/media/gpu/vaapi/vaapi_image_decode_accelerator_worker.cc b/media/gpu/vaapi/vaapi_image_decode_accelerator_worker.cc
index cce88ddb..a88ad3d 100644
--- a/media/gpu/vaapi/vaapi_image_decode_accelerator_worker.cc
+++ b/media/gpu/vaapi/vaapi_image_decode_accelerator_worker.cc
@@ -127,19 +127,13 @@
                           VAJDAWorkerDecoderFailure::kVaapiError);
   VaapiImageDecoderVector decoders;
 
-  if (base::FeatureList::IsEnabled(
-          features::kVaapiJpegImageDecodeAcceleration)) {
-    auto jpeg_decoder = std::make_unique<VaapiJpegDecoder>();
-    if (jpeg_decoder->Initialize(uma_cb))
-      decoders.push_back(std::move(jpeg_decoder));
-  }
+  auto jpeg_decoder = std::make_unique<VaapiJpegDecoder>();
+  if (jpeg_decoder->Initialize(uma_cb))
+    decoders.push_back(std::move(jpeg_decoder));
 
-  if (base::FeatureList::IsEnabled(
-          features::kVaapiWebPImageDecodeAcceleration)) {
-    auto webp_decoder = std::make_unique<VaapiWebPDecoder>();
-    if (webp_decoder->Initialize(uma_cb))
-      decoders.push_back(std::move(webp_decoder));
-  }
+  auto webp_decoder = std::make_unique<VaapiWebPDecoder>();
+  if (webp_decoder->Initialize(uma_cb))
+    decoders.push_back(std::move(webp_decoder));
 
   // If there are no decoders due to disabled flags or initialization failure,
   // return nullptr.
@@ -183,10 +177,15 @@
       base::make_span<const uint8_t>(encoded_data.data(), encoded_data.size());
   auto result = decoders_.end();
 
-  if (IsJpegImage(encoded_data_span))
+  if (base::FeatureList::IsEnabled(
+          features::kVaapiJpegImageDecodeAcceleration) &&
+      IsJpegImage(encoded_data_span)) {
     result = decoders_.find(gpu::ImageDecodeAcceleratorType::kJpeg);
-  else if (IsLossyWebPImage(encoded_data_span))
+  } else if (base::FeatureList::IsEnabled(
+                 features::kVaapiWebPImageDecodeAcceleration) &&
+             IsLossyWebPImage(encoded_data_span)) {
     result = decoders_.find(gpu::ImageDecodeAcceleratorType::kWebP);
+  }
 
   return result == decoders_.end() ? nullptr : result->second.get();
 }
diff --git a/media/gpu/vaapi/vaapi_image_decode_accelerator_worker_unittest.cc b/media/gpu/vaapi/vaapi_image_decode_accelerator_worker_unittest.cc
index ceafd0b..d7bcd05 100644
--- a/media/gpu/vaapi/vaapi_image_decode_accelerator_worker_unittest.cc
+++ b/media/gpu/vaapi/vaapi_image_decode_accelerator_worker_unittest.cc
@@ -19,7 +19,9 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
+#include "gpu/config/gpu_finch_features.h"
 #include "gpu/config/gpu_info.h"
 #include "gpu/ipc/service/image_decode_accelerator_worker.h"
 #include "media/gpu/vaapi/vaapi_image_decode_accelerator_worker.h"
@@ -129,6 +131,10 @@
 class VaapiImageDecodeAcceleratorWorkerTest : public testing::Test {
  public:
   VaapiImageDecodeAcceleratorWorkerTest() {
+    feature_list_.InitWithFeatures(
+        {features::kVaapiJpegImageDecodeAcceleration,
+         features::kVaapiWebPImageDecodeAcceleration} /* enabled_features */,
+        {} /* disabled_features */);
     VaapiImageDecoderVector decoders;
     decoders.push_back(std::make_unique<StrictMock<MockVaapiImageDecoder>>(
         gpu::ImageDecodeAcceleratorType::kJpeg));
@@ -160,6 +166,7 @@
 
  protected:
   base::test::TaskEnvironment task_environment_;
+  base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<VaapiImageDecodeAcceleratorWorker> worker_;
 
   DISALLOW_COPY_AND_ASSIGN(VaapiImageDecodeAcceleratorWorkerTest);
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc
index c98c29e..0a706efc 100644
--- a/net/cert/cert_verify_proc_unittest.cc
+++ b/net/cert/cert_verify_proc_unittest.cc
@@ -902,36 +902,64 @@
     return true;
   }
 
-  bool WeakKeysAreInvalid() const {
-#if defined(OS_MACOSX) and !defined(OS_IOS)
-    // Starting with Mac OS 10.12, certs with weak keys are treated as
-    // (recoverable) invalid certificate errors.
-    if (verify_proc_type() == CERT_VERIFY_PROC_MAC &&
-        base::mac::IsAtLeastOS10_12()) {
-      return true;
-    }
-#endif
-    return false;
-  }
-
-  int GetMinimumRsaDsaKeySize() const {
+  // Returns true if the RSA/DSA keysize will be considered weak on the current
+  // platform. IsInvalidRsaDsaKeySize should be checked prior, since some very
+  // weak keys may be considered invalid.
+  bool IsWeakRsaDsaKeySize(int size) const {
 #if defined(OS_IOS)
     // Beginning with iOS 13, the minimum key size for RSA/DSA algorithms is
     // 2048 bits. See https://support.apple.com/en-us/HT210176
     if (verify_proc_type() == CERT_VERIFY_PROC_IOS &&
         base::ios::IsRunningOnIOS13OrLater()) {
-      return 2048;
+      return size < 2048;
     }
 #elif defined(OS_MACOSX)
     // Beginning with macOS 10.15, the minimum key size for RSA/DSA algorithms
     // is 2048 bits. See https://support.apple.com/en-us/HT210176
     if (verify_proc_type() == CERT_VERIFY_PROC_MAC &&
         base::mac::IsAtLeastOS10_15()) {
-      return 2048;
+      return size < 2048;
     }
 #endif
 
-    return 1024;
+    return size < 1024;
+  }
+
+  // Returns true if the RSA/DSA keysize will be considered invalid on the
+  // current platform.
+  bool IsInvalidRsaDsaKeySize(int size) const {
+#if defined(OS_MACOSX) and !defined(OS_IOS)
+    // Starting with Mac OS 10.12, certs with keys < 1024 are invalid.
+    if (verify_proc_type() == CERT_VERIFY_PROC_MAC &&
+        base::mac::IsAtLeastOS10_12()) {
+      return size < 1024;
+    }
+#endif
+
+    // This platform does not mark certificates with weak keys as invalid.
+    return false;
+  }
+
+  static bool ParseKeyType(const std::string& key_type,
+                           std::string* type,
+                           int* size) {
+    size_t pos = key_type.find("-");
+    std::string size_str = key_type.substr(0, pos);
+    *type = key_type.substr(pos + 1);
+    return base::StringToInt(size_str, size);
+  }
+
+  // Some platforms may reject certificates with very weak keys as invalid.
+  bool IsInvalidKeyType(const std::string& key_type) const {
+    std::string type;
+    int size = 0;
+    if (!ParseKeyType(key_type, &type, &size))
+      return false;
+
+    if (type == "rsa" || type == "dsa")
+      return IsInvalidRsaDsaKeySize(size);
+
+    return false;
   }
 
   // Currently, only RSA and DSA keys are checked for weakness, and our example
@@ -939,17 +967,17 @@
   //
   // Note that this means there may be false negatives: keys for other
   // algorithms and which are weak will pass this test.
+  //
+  // Also, IsInvalidKeyType should be checked prior, since some weak keys may be
+  // considered invalid.
   bool IsWeakKeyType(const std::string& key_type) const {
-    size_t pos = key_type.find("-");
-    std::string size_str = key_type.substr(0, pos);
-    std::string type = key_type.substr(pos + 1);
+    std::string type;
     int size = 0;
-
-    if (!base::StringToInt(size_str, &size))
+    if (!ParseKeyType(key_type, &type, &size))
       return false;
 
     if (type == "rsa" || type == "dsa")
-      return size < GetMinimumRsaDsaKeySize();
+      return IsWeakRsaDsaKeySize(size);
 
     return false;
   }
@@ -1463,17 +1491,15 @@
                          CRLSet::BuiltinCRLSet().get(), CertificateList(),
                          &verify_result);
 
-      if (IsWeakKeyType(*ee_type) || IsWeakKeyType(*signer_type)) {
+      if (IsInvalidKeyType(*ee_type) || IsInvalidKeyType(*signer_type)) {
         EXPECT_NE(OK, error);
-        if (WeakKeysAreInvalid()) {
-          EXPECT_EQ(CERT_STATUS_INVALID,
-                    verify_result.cert_status & CERT_STATUS_INVALID);
-
-        } else {
-          EXPECT_EQ(CERT_STATUS_WEAK_KEY,
-                    verify_result.cert_status & CERT_STATUS_WEAK_KEY);
-          EXPECT_EQ(0u, verify_result.cert_status & CERT_STATUS_INVALID);
-        }
+        EXPECT_EQ(CERT_STATUS_INVALID,
+                  verify_result.cert_status & CERT_STATUS_INVALID);
+      } else if (IsWeakKeyType(*ee_type) || IsWeakKeyType(*signer_type)) {
+        EXPECT_NE(OK, error);
+        EXPECT_EQ(CERT_STATUS_WEAK_KEY,
+                  verify_result.cert_status & CERT_STATUS_WEAK_KEY);
+        EXPECT_EQ(0u, verify_result.cert_status & CERT_STATUS_INVALID);
       } else {
         EXPECT_THAT(error, IsOk());
         EXPECT_EQ(0U, verify_result.cert_status & CERT_STATUS_WEAK_KEY);
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 5962c61..41e2b3f 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -91,11 +91,17 @@
   INITIAL_RTT_SOURCE_MAX,
 };
 
-enum class EmptyStaleResultLocation {
-  kResolveHost = 0,
-  kMatchFreshResult = 1,
-  kNotEmpty = 2,
-  kMaxValue = kNotEmpty,
+// These values are logged to UMA. Entries should not be renumbered and
+// numeric values should never be reused. Please keep in sync with
+// "ConnectionStateAfterDNS" in src/tools/metrics/histograms/enums.xml.
+enum class ConnectionStateAfterDNS {
+  kDNSFailed = 0,
+  kIpPooled = 1,
+  kWaitingForCryptoDnsMatched = 2,
+  kWaitingForCryptoDnsNoMatch = 3,
+  kCryptoFinishedDnsMatch = 4,
+  kCryptoFinishedDnsNoMatch = 5,
+  kMaxValue = kCryptoFinishedDnsNoMatch,
 };
 
 // The maximum receive window sizes for QUIC sessions and streams.
@@ -159,13 +165,8 @@
   UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ConnectionIpPooled", pooled);
 }
 
-void LogEmptyStaleResult(EmptyStaleResultLocation location) {
-  UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.StaleHostResolveFailed", location);
-}
-
-void LogSessionAvailabilityWhenValidatingHost(bool available) {
-  UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.SessionAvailableWhenValidatingDNS",
-                        available);
+void LogRacingStatus(ConnectionStateAfterDNS status) {
+  UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionStateAfterDNS", status);
 }
 
 void SetInitialRttEstimate(base::TimeDelta estimate,
@@ -427,29 +428,19 @@
     if (session_) {
       QuicChromiumClientSession* session = session_;
       session_ = nullptr;
-      if (session) {
-        session->CloseSessionOnErrorLater(
-            ERR_ABORTED, quic::QUIC_STALE_CONNECTION_CANCELLED,
-            quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-      }
+      session->CloseSessionOnErrorLater(
+          ERR_ABORTED, quic::QUIC_STALE_CONNECTION_CANCELLED,
+          quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
     }
   }
 
   bool DoesPeerAddressMatchWithFreshAddressList() {
-    LogSessionAvailabilityWhenValidatingHost(session_ != nullptr);
-
     if (!session_)
       return false;
 
     std::vector<net::IPEndPoint> endpoints =
         fresh_resolve_host_request_->GetAddressResults().value().endpoints();
 
-    if (!resolve_host_request_->GetAddressResults()) {
-      LogEmptyStaleResult(EmptyStaleResultLocation::kMatchFreshResult);
-      return false;
-    }
-
-    LogEmptyStaleResult(EmptyStaleResultLocation::kNotEmpty);
     IPEndPoint stale_address =
         resolve_host_request_->GetAddressResults().value().front();
 
@@ -628,6 +619,7 @@
     DCHECK(race_stale_dns_on_connection_);
     dns_resolution_end_time_ = base::TimeTicks::Now();
     if (rv != OK) {
+      LogRacingStatus(ConnectionStateAfterDNS::kDNSFailed);
       CloseStaleHostConnection();
       resolve_host_request_ = std::move(fresh_resolve_host_request_);
       io_state_ = STATE_RESOLVE_HOST_COMPLETE;
@@ -636,6 +628,7 @@
                    fresh_resolve_host_request_->GetAddressResults().value())) {
       // Session with resolved IP has already existed, so close racing
       // connection, run callback, and return.
+      LogRacingStatus(ConnectionStateAfterDNS::kIpPooled);
       LogConnectionIpPooling(true);
       CloseStaleHostConnection();
       if (!callback_.is_null())
@@ -645,10 +638,12 @@
       // Case where host resolution returns successfully, but stale connection
       // hasn't finished yet.
       if (DoesPeerAddressMatchWithFreshAddressList()) {
+        LogRacingStatus(ConnectionStateAfterDNS::kWaitingForCryptoDnsMatched);
         LogStaleAndFreshHostMatched(true);
         fresh_resolve_host_request_ = nullptr;
         return;
       }
+      LogRacingStatus(ConnectionStateAfterDNS::kWaitingForCryptoDnsNoMatch);
       LogStaleAndFreshHostMatched(false);
       CloseStaleHostConnection();
       resolve_host_request_ = std::move(fresh_resolve_host_request_);
@@ -751,7 +746,6 @@
   // Check to make sure stale host request does produce valid results.
   if (!resolve_host_request_->GetAddressResults()) {
     LogStaleHostRacing(false);
-    LogEmptyStaleResult(EmptyStaleResultLocation::kResolveHost);
     resolve_host_request_ = std::move(fresh_resolve_host_request_);
     return fresh_rv;
   }
@@ -850,6 +844,7 @@
 // have finished successfully.
 int QuicStreamFactory::Job::DoValidateHost() {
   if (DoesPeerAddressMatchWithFreshAddressList()) {
+    LogRacingStatus(ConnectionStateAfterDNS::kCryptoFinishedDnsMatch);
     LogStaleAndFreshHostMatched(true);
     fresh_resolve_host_request_ = nullptr;
     host_resolution_finished_ = true;
@@ -857,6 +852,7 @@
     return OK;
   }
 
+  LogRacingStatus(ConnectionStateAfterDNS::kCryptoFinishedDnsNoMatch);
   LogStaleAndFreshHostMatched(false);
   resolve_host_request_ = std::move(fresh_resolve_host_request_);
   CloseStaleHostConnection();
diff --git a/net/test/url_request/url_request_test_job_backed_by_file_unittest.cc b/net/test/url_request/url_request_test_job_backed_by_file_unittest.cc
index 56a8079..db0d808 100644
--- a/net/test/url_request/url_request_test_job_backed_by_file_unittest.cc
+++ b/net/test/url_request/url_request_test_job_backed_by_file_unittest.cc
@@ -126,18 +126,6 @@
     return job;
   }
 
-  URLRequestJob* MaybeInterceptRedirect(URLRequest* request,
-                                        NetworkDelegate* network_delegate,
-                                        const GURL& location) const override {
-    return nullptr;
-  }
-
-  URLRequestJob* MaybeInterceptResponse(
-      URLRequest* request,
-      NetworkDelegate* network_delegate) const override {
-    return nullptr;
-  }
-
   bool IsHandledProtocol(const std::string& scheme) const override {
     return scheme == "file";
   }
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 4acd648..292df77 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -705,13 +705,6 @@
   job_->Start();
 }
 
-void URLRequest::Restart() {
-  // Should only be called if the original job didn't make any progress.
-  DCHECK(job_.get() && !job_->has_response_started());
-  RestartWithJob(
-      URLRequestJobManager::GetInstance()->CreateJob(this, network_delegate_));
-}
-
 void URLRequest::RestartWithJob(URLRequestJob* job) {
   DCHECK(job->request() == this);
   PrepareToRestart();
@@ -831,17 +824,9 @@
 void URLRequest::NotifyReceivedRedirect(const RedirectInfo& redirect_info,
                                         bool* defer_redirect) {
   is_redirecting_ = true;
-
-  URLRequestJob* job =
-      URLRequestJobManager::GetInstance()->MaybeInterceptRedirect(
-          this, network_delegate_, redirect_info.new_url);
-  if (job) {
-    RestartWithJob(job);
-  } else {
-    OnCallToDelegate(NetLogEventType::URL_REQUEST_DELEGATE_RECEIVED_REDIRECT);
-    delegate_->OnReceivedRedirect(this, redirect_info, defer_redirect);
-    // |this| may be have been destroyed here.
-  }
+  OnCallToDelegate(NetLogEventType::URL_REQUEST_DELEGATE_RECEIVED_REDIRECT);
+  delegate_->OnReceivedRedirect(this, redirect_info, defer_redirect);
+  // |this| may be have been destroyed here.
 }
 
 void URLRequest::NotifyResponseStarted(const URLRequestStatus& status) {
@@ -859,28 +844,21 @@
   net_log_.EndEventWithNetErrorCode(NetLogEventType::URL_REQUEST_START_JOB,
                                     net_error);
 
-  URLRequestJob* job =
-      URLRequestJobManager::GetInstance()->MaybeInterceptResponse(
-          this, network_delegate_);
-  if (job) {
-    RestartWithJob(job);
-  } else {
-    // In some cases (e.g. an event was canceled), we might have sent the
-    // completion event and receive a NotifyResponseStarted() later.
-    if (!has_notified_completion_ && status_.is_success()) {
-      if (network_delegate_)
-        network_delegate_->NotifyResponseStarted(this, net_error);
-    }
-
-    // Notify in case the entire URL Request has been finished.
-    if (!has_notified_completion_ && !status_.is_success())
-      NotifyRequestCompleted();
-
-    OnCallToDelegate(NetLogEventType::URL_REQUEST_DELEGATE_RESPONSE_STARTED);
-    delegate_->OnResponseStarted(this, net_error);
-    // Nothing may appear below this line as OnResponseStarted may delete
-    // |this|.
+  // In some cases (e.g. an event was canceled), we might have sent the
+  // completion event and receive a NotifyResponseStarted() later.
+  if (!has_notified_completion_ && status_.is_success()) {
+    if (network_delegate_)
+      network_delegate_->NotifyResponseStarted(this, net_error);
   }
+
+  // Notify in case the entire URL Request has been finished.
+  if (!has_notified_completion_ && !status_.is_success())
+    NotifyRequestCompleted();
+
+  OnCallToDelegate(NetLogEventType::URL_REQUEST_DELEGATE_RESPONSE_STARTED);
+  delegate_->OnResponseStarted(this, net_error);
+  // Nothing may appear below this line as OnResponseStarted may delete
+  // |this|.
 }
 
 void URLRequest::FollowDeferredRedirect(
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index 917c647..55bbac26 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -789,10 +789,6 @@
   void NotifyReceivedRedirect(const RedirectInfo& redirect_info,
                               bool* defer_redirect);
 
-  // Allow an interceptor's URLRequestJob to restart this request.
-  // Should only be called if the original job has not started a response.
-  void Restart();
-
  private:
   friend class URLRequestJob;
   friend class URLRequestContext;
diff --git a/net/url_request/url_request_ftp_job_unittest.cc b/net/url_request/url_request_ftp_job_unittest.cc
index e03f4545..31e91ab7a 100644
--- a/net/url_request/url_request_ftp_job_unittest.cc
+++ b/net/url_request/url_request_ftp_job_unittest.cc
@@ -126,18 +126,6 @@
     return new URLRequestFtpJob(request, network_delegate, factory, auth_cache);
   }
 
-  URLRequestJob* MaybeInterceptRedirect(URLRequest* request,
-                                        NetworkDelegate* network_delegate,
-                                        const GURL& location) const override {
-    return nullptr;
-  }
-
-  URLRequestJob* MaybeInterceptResponse(
-      URLRequest* request,
-      NetworkDelegate* network_delegate) const override {
-    return nullptr;
-  }
-
   bool IsHandledProtocol(const std::string& scheme) const override {
     return scheme == "ftp";
   }
diff --git a/net/url_request/url_request_intercepting_job_factory.cc b/net/url_request/url_request_intercepting_job_factory.cc
index 6651436d..4f8799b 100644
--- a/net/url_request/url_request_intercepting_job_factory.cc
+++ b/net/url_request/url_request_intercepting_job_factory.cc
@@ -44,33 +44,6 @@
       scheme, request, network_delegate);
 }
 
-URLRequestJob* URLRequestInterceptingJobFactory::MaybeInterceptRedirect(
-    URLRequest* request,
-    NetworkDelegate* network_delegate,
-    const GURL& location) const {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  URLRequestJob* job = interceptor_->MaybeInterceptRedirect(request,
-                                                            network_delegate,
-                                                            location);
-  if (job)
-    return job;
-  return job_factory_->MaybeInterceptRedirect(request,
-                                              network_delegate,
-                                              location);
-}
-
-URLRequestJob* URLRequestInterceptingJobFactory::MaybeInterceptResponse(
-    URLRequest* request,
-    NetworkDelegate* network_delegate) const {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  URLRequestJob* job = interceptor_->MaybeInterceptResponse(request,
-                                                            network_delegate);
-  if (job)
-    return job;
-  return job_factory_->MaybeInterceptResponse(request,
-                                              network_delegate);
-}
-
 bool URLRequestInterceptingJobFactory::IsHandledProtocol(
     const std::string& scheme) const {
   return job_factory_->IsHandledProtocol(scheme);
diff --git a/net/url_request/url_request_intercepting_job_factory.h b/net/url_request/url_request_intercepting_job_factory.h
index 652e8862..30ae394 100644
--- a/net/url_request/url_request_intercepting_job_factory.h
+++ b/net/url_request/url_request_intercepting_job_factory.h
@@ -29,6 +29,8 @@
 // This class is only intended for use in intercepting requests before they
 // are passed on to their default ProtocolHandler.  Each supported scheme should
 // have its own ProtocolHandler.
+//
+// TODO(mmenke): Delete this class.
 class NET_EXPORT URLRequestInterceptingJobFactory
     : public URLRequestJobFactory {
  public:
@@ -48,15 +50,6 @@
       URLRequest* request,
       NetworkDelegate* network_delegate) const override;
 
-  URLRequestJob* MaybeInterceptRedirect(
-      URLRequest* request,
-      NetworkDelegate* network_delegate,
-      const GURL& location) const override;
-
-  URLRequestJob* MaybeInterceptResponse(
-      URLRequest* request,
-      NetworkDelegate* network_delegate) const override;
-
   bool IsHandledProtocol(const std::string& scheme) const override;
   bool IsSafeRedirectTarget(const GURL& location) const override;
 
diff --git a/net/url_request/url_request_interceptor.cc b/net/url_request/url_request_interceptor.cc
index 29801d7..fda2553 100644
--- a/net/url_request/url_request_interceptor.cc
+++ b/net/url_request/url_request_interceptor.cc
@@ -10,16 +10,4 @@
 
 URLRequestInterceptor::~URLRequestInterceptor() = default;
 
-URLRequestJob* URLRequestInterceptor::MaybeInterceptRedirect(
-    URLRequest* request,
-    NetworkDelegate* network_delegate,
-    const GURL& location) const {
-  return nullptr;
-}
-
-URLRequestJob* URLRequestInterceptor::MaybeInterceptResponse(
-    URLRequest* request, NetworkDelegate* network_delegate) const {
-  return nullptr;
-}
-
 }  // namespace net
diff --git a/net/url_request/url_request_interceptor.h b/net/url_request/url_request_interceptor.h
index f7d5275..9ed1670 100644
--- a/net/url_request/url_request_interceptor.h
+++ b/net/url_request/url_request_interceptor.h
@@ -8,17 +8,18 @@
 #include "base/macros.h"
 #include "net/base/net_export.h"
 
-class GURL;
-
 namespace net {
 
 class URLRequest;
 class URLRequestJob;
 class NetworkDelegate;
 
-// A URLRequestInterceptor is given a chance to create a URLRequestJob to
-// handle URLRequests before they're handed off to the ProtocolHandler for
+// In tests, URLRequestFilter lets URLRequestInterceptors create URLRequestJobs
+// to handle URLRequests before they're handed off to the ProtocolHandler for
 // the request's scheme.
+//
+// TODO(mmenke):  Only include this file in test targets. Also consider using
+// callbacks instead, or even removing URLRequestFilter.
 class NET_EXPORT URLRequestInterceptor {
  public:
   URLRequestInterceptor();
@@ -30,20 +31,6 @@
   virtual URLRequestJob* MaybeInterceptRequest(
       URLRequest* request, NetworkDelegate* network_delegate) const = 0;
 
-  // Returns a URLRequestJob to handle |request|, if the interceptor wants to
-  // take over the handling of the request after a redirect is received,
-  // instead of using the default ProtocolHandler. Otherwise, returns NULL.
-  virtual URLRequestJob* MaybeInterceptRedirect(
-      URLRequest* request,
-      NetworkDelegate* network_delegate,
-      const GURL& location) const;
-
-  // Returns a URLRequestJob to handle |request, if the interceptor wants to
-  // take over the handling of the request after a response has started,
-  // instead of using the default ProtocolHandler. Otherwise, returns NULL.
-  virtual URLRequestJob* MaybeInterceptResponse(
-      URLRequest* request, NetworkDelegate* network_delegate) const;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(URLRequestInterceptor);
 };
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index a285061..88b93f7 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -571,12 +571,6 @@
   }
 }
 
-void URLRequestJob::NotifyRestartRequired() {
-  DCHECK(!has_handled_response_);
-  if (GetStatus().status() != URLRequestStatus::CANCELED)
-    request_->Restart();
-}
-
 void URLRequestJob::OnCallToDelegate(NetLogEventType type) {
   request_->OnCallToDelegate(type);
 }
diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h
index e2068bc..68a36ec4 100644
--- a/net/url_request/url_request_job.h
+++ b/net/url_request/url_request_job.h
@@ -285,10 +285,6 @@
   // that we were canceled.
   void NotifyCanceled();
 
-  // Notifies the job the request should be restarted.
-  // Should only be called if the job has not started a response.
-  void NotifyRestartRequired();
-
   // See corresponding functions in url_request.h.
   void OnCallToDelegate(NetLogEventType type);
   void OnCallToDelegateComplete();
diff --git a/net/url_request/url_request_job_factory.h b/net/url_request/url_request_job_factory.h
index eabdfe0..12e3e15 100644
--- a/net/url_request/url_request_job_factory.h
+++ b/net/url_request/url_request_job_factory.h
@@ -46,15 +46,6 @@
       URLRequest* request,
       NetworkDelegate* network_delegate) const = 0;
 
-  virtual URLRequestJob* MaybeInterceptRedirect(
-      URLRequest* request,
-      NetworkDelegate* network_delegate,
-      const GURL& location) const = 0;
-
-  virtual URLRequestJob* MaybeInterceptResponse(
-      URLRequest* request,
-      NetworkDelegate* network_delegate) const = 0;
-
   virtual bool IsHandledProtocol(const std::string& scheme) const = 0;
 
   virtual bool IsSafeRedirectTarget(const GURL& location) const = 0;
diff --git a/net/url_request/url_request_job_factory_impl.cc b/net/url_request/url_request_job_factory_impl.cc
index ad38c62b..5d879d7 100644
--- a/net/url_request/url_request_job_factory_impl.cc
+++ b/net/url_request/url_request_job_factory_impl.cc
@@ -60,19 +60,6 @@
   return it->second->MaybeCreateJob(request, network_delegate);
 }
 
-URLRequestJob* URLRequestJobFactoryImpl::MaybeInterceptRedirect(
-    URLRequest* request,
-    NetworkDelegate* network_delegate,
-    const GURL& location) const {
-  return nullptr;
-}
-
-URLRequestJob* URLRequestJobFactoryImpl::MaybeInterceptResponse(
-    URLRequest* request,
-    NetworkDelegate* network_delegate) const {
-  return nullptr;
-}
-
 bool URLRequestJobFactoryImpl::IsHandledProtocol(
     const std::string& scheme) const {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/net/url_request/url_request_job_factory_impl.h b/net/url_request/url_request_job_factory_impl.h
index 3ff3c92..45fe2a5b 100644
--- a/net/url_request/url_request_job_factory_impl.h
+++ b/net/url_request/url_request_job_factory_impl.h
@@ -34,15 +34,6 @@
       URLRequest* request,
       NetworkDelegate* network_delegate) const override;
 
-  URLRequestJob* MaybeInterceptRedirect(
-      URLRequest* request,
-      NetworkDelegate* network_delegate,
-      const GURL& location) const override;
-
-  URLRequestJob* MaybeInterceptResponse(
-      URLRequest* request,
-      NetworkDelegate* network_delegate) const override;
-
   bool IsHandledProtocol(const std::string& scheme) const override;
   bool IsSafeRedirectTarget(const GURL& location) const override;
 
diff --git a/net/url_request/url_request_job_manager.cc b/net/url_request/url_request_job_manager.cc
index da609d2..8cc17ef 100644
--- a/net/url_request/url_request_job_manager.cc
+++ b/net/url_request/url_request_job_manager.cc
@@ -92,56 +92,6 @@
   return new URLRequestErrorJob(request, network_delegate, ERR_FAILED);
 }
 
-URLRequestJob* URLRequestJobManager::MaybeInterceptRedirect(
-    URLRequest* request,
-    NetworkDelegate* network_delegate,
-    const GURL& location) const {
-  DCHECK(IsAllowedThread());
-  if (!request->url().is_valid() ||
-      request->status().status() == URLRequestStatus::CANCELED) {
-    return nullptr;
-  }
-
-  const URLRequestJobFactory* job_factory = nullptr;
-  job_factory = request->context()->job_factory();
-
-  const std::string& scheme = request->url().scheme();  // already lowercase
-  if (!job_factory->IsHandledProtocol(scheme))
-    return nullptr;
-
-  URLRequestJob* job =
-      request->context()->job_factory()->MaybeInterceptRedirect(
-          request, network_delegate, location);
-  if (job)
-    return job;
-
-  return nullptr;
-}
-
-URLRequestJob* URLRequestJobManager::MaybeInterceptResponse(
-    URLRequest* request, NetworkDelegate* network_delegate) const {
-  DCHECK(IsAllowedThread());
-  if (!request->url().is_valid() ||
-      request->status().status() == URLRequestStatus::CANCELED) {
-    return nullptr;
-  }
-
-  const URLRequestJobFactory* job_factory = nullptr;
-  job_factory = request->context()->job_factory();
-
-  const std::string& scheme = request->url().scheme();  // already lowercase
-  if (!job_factory->IsHandledProtocol(scheme))
-    return nullptr;
-
-  URLRequestJob* job =
-      request->context()->job_factory()->MaybeInterceptResponse(
-          request, network_delegate);
-  if (job)
-    return job;
-
-  return nullptr;
-}
-
 // static
 bool URLRequestJobManager::SupportsScheme(const std::string& scheme) {
   for (size_t i = 0; i < base::size(kBuiltinFactories); ++i) {
diff --git a/net/url_request/url_request_job_manager.h b/net/url_request/url_request_job_manager.h
index 4460060d..9c0fdc6 100644
--- a/net/url_request/url_request_job_manager.h
+++ b/net/url_request/url_request_job_manager.h
@@ -37,19 +37,6 @@
   URLRequestJob* CreateJob(URLRequest* request,
                            NetworkDelegate* network_delegate) const;
 
-  // Allows interceptors to hijack the request after examining the new location
-  // of a redirect. Returns NULL if no interceptor intervenes.
-  URLRequestJob* MaybeInterceptRedirect(URLRequest* request,
-                                        NetworkDelegate* network_delegate,
-                                        const GURL& location) const;
-
-  // Allows interceptors to hijack the request after examining the response
-  // status and headers. This is also called when there is no server response
-  // at all to allow interception of failed requests due to network errors.
-  // Returns NULL if no interceptor intervenes.
-  URLRequestJob* MaybeInterceptResponse(
-      URLRequest* request, NetworkDelegate* network_delegate) const;
-
   // Returns true if the manager has a built-in handler for |scheme|.
   static bool SupportsScheme(const std::string& scheme);
 
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index ecf3eb8..84bba55 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -927,42 +927,6 @@
   EXPECT_TRUE(d.request_failed());
 }
 
-// Custom URLRequestJobs for use with interceptor tests
-class RestartTestJob : public URLRequestTestJob {
- public:
-  RestartTestJob(URLRequest* request, NetworkDelegate* network_delegate)
-    : URLRequestTestJob(request, network_delegate, true) {}
- protected:
-  void StartAsync() override { this->NotifyRestartRequired(); }
- private:
-  ~RestartTestJob() override = default;
-};
-
-class CancelTestJob : public URLRequestTestJob {
- public:
-  explicit CancelTestJob(URLRequest* request, NetworkDelegate* network_delegate)
-    : URLRequestTestJob(request, network_delegate, true) {}
- protected:
-  void StartAsync() override { request_->Cancel(); }
- private:
-  ~CancelTestJob() override = default;
-};
-
-class CancelThenRestartTestJob : public URLRequestTestJob {
- public:
-  explicit CancelThenRestartTestJob(URLRequest* request,
-                                    NetworkDelegate* network_delegate)
-      : URLRequestTestJob(request, network_delegate, true) {
-  }
- protected:
-  void StartAsync() override {
-    request_->Cancel();
-    this->NotifyRestartRequired();
-  }
- private:
-  ~CancelThenRestartTestJob() override = default;
-};
-
 // An Interceptor for use with interceptor tests.
 class MockURLRequestInterceptor : public URLRequestInterceptor {
  public:
@@ -975,35 +939,7 @@
     return URLRequestTestJob::test_headers();
   }
 
-  static std::string redirect_data() {
-    return std::string();
-  }
-
-  static std::string redirect_headers() {
-    return URLRequestTestJob::test_redirect_headers();
-  }
-
-  static std::string error_data() {
-    return std::string("ohhh nooooo mr. bill!");
-  }
-
-  static std::string error_headers() {
-    return URLRequestTestJob::test_error_headers();
-  }
-
-  MockURLRequestInterceptor()
-      : intercept_main_request_(false), restart_main_request_(false),
-        cancel_main_request_(false), cancel_then_restart_main_request_(false),
-        simulate_main_network_error_(false),
-        intercept_redirect_(false), cancel_redirect_request_(false),
-        intercept_final_response_(false), cancel_final_request_(false),
-        use_url_request_http_job_(false),
-        did_intercept_main_(false), did_restart_main_(false),
-        did_cancel_main_(false), did_cancel_then_restart_main_(false),
-        did_simulate_error_main_(false),
-        did_intercept_redirect_(false), did_cancel_redirect_(false),
-        did_intercept_final_(false), did_cancel_final_(false) {
-  }
+  MockURLRequestInterceptor() {}
 
   ~MockURLRequestInterceptor() override = default;
 
@@ -1011,239 +947,19 @@
   URLRequestJob* MaybeInterceptRequest(
       URLRequest* request,
       NetworkDelegate* network_delegate) const override {
-    if (restart_main_request_) {
-      restart_main_request_ = false;
-      did_restart_main_ = true;
-      return new RestartTestJob(request, network_delegate);
-    }
-    if (cancel_main_request_) {
-      cancel_main_request_ = false;
-      did_cancel_main_ = true;
-      return new CancelTestJob(request, network_delegate);
-    }
-    if (cancel_then_restart_main_request_) {
-      cancel_then_restart_main_request_ = false;
-      did_cancel_then_restart_main_ = true;
-      return new CancelThenRestartTestJob(request, network_delegate);
-    }
-    if (simulate_main_network_error_) {
-      simulate_main_network_error_ = false;
-      did_simulate_error_main_ = true;
-      if (use_url_request_http_job_) {
-        return URLRequestHttpJob::Factory(request, network_delegate, "http");
-      }
-      // This job will result in error since the requested URL is not one of the
-      // URLs supported by these tests.
-      return new URLRequestTestJob(request, network_delegate, true);
-    }
-    if (!intercept_main_request_)
-      return nullptr;
-    intercept_main_request_ = false;
-    did_intercept_main_ = true;
-    URLRequestTestJob* job =  new URLRequestTestJob(request,
-                                                    network_delegate,
-                                                    main_headers_,
-                                                    main_data_,
-                                                    true);
+    URLRequestTestJob* job = new URLRequestTestJob(
+        request, network_delegate, ok_headers(), ok_data(), true);
     job->set_load_timing_info(main_request_load_timing_info_);
     return job;
   }
 
-  URLRequestJob* MaybeInterceptRedirect(URLRequest* request,
-                                        NetworkDelegate* network_delegate,
-                                        const GURL& location) const override {
-    if (cancel_redirect_request_) {
-      cancel_redirect_request_ = false;
-      did_cancel_redirect_ = true;
-      return new CancelTestJob(request, network_delegate);
-    }
-    if (!intercept_redirect_)
-      return nullptr;
-    intercept_redirect_ = false;
-    did_intercept_redirect_ = true;
-    if (use_url_request_http_job_) {
-      return URLRequestHttpJob::Factory(request, network_delegate, "http");
-    }
-    return new URLRequestTestJob(request,
-                                 network_delegate,
-                                 redirect_headers_,
-                                 redirect_data_,
-                                 true);
-  }
-
-  URLRequestJob* MaybeInterceptResponse(
-      URLRequest* request,
-      NetworkDelegate* network_delegate) const override {
-    if (cancel_final_request_) {
-      cancel_final_request_ = false;
-      did_cancel_final_ = true;
-      return new CancelTestJob(request, network_delegate);
-    }
-    if (!intercept_final_response_)
-      return nullptr;
-    intercept_final_response_ = false;
-    did_intercept_final_ = true;
-    if (use_url_request_http_job_) {
-      return URLRequestHttpJob::Factory(request, network_delegate, "http");
-    }
-    return new URLRequestTestJob(request,
-                                 network_delegate,
-                                 final_headers_,
-                                 final_data_,
-                                 true);
-  }
-
-  void set_intercept_main_request(bool intercept_main_request) {
-    intercept_main_request_ = intercept_main_request;
-  }
-
-  void set_main_headers(const std::string& main_headers) {
-    main_headers_ = main_headers;
-  }
-
-  void set_main_data(const std::string& main_data) {
-    main_data_ = main_data;
-  }
-
   void set_main_request_load_timing_info(
       const LoadTimingInfo& main_request_load_timing_info) {
     main_request_load_timing_info_ = main_request_load_timing_info;
   }
 
-  void set_restart_main_request(bool restart_main_request) {
-    restart_main_request_ = restart_main_request;
-  }
-
-  void set_cancel_main_request(bool cancel_main_request) {
-    cancel_main_request_ = cancel_main_request;
-  }
-
-  void set_cancel_then_restart_main_request(
-      bool cancel_then_restart_main_request) {
-    cancel_then_restart_main_request_ = cancel_then_restart_main_request;
-  }
-
-  void set_simulate_main_network_error(bool simulate_main_network_error) {
-    simulate_main_network_error_ = simulate_main_network_error;
-  }
-
-  void set_intercept_redirect(bool intercept_redirect) {
-    intercept_redirect_ = intercept_redirect;
-  }
-
-  void set_redirect_headers(const std::string& redirect_headers) {
-    redirect_headers_ = redirect_headers;
-  }
-
-  void set_redirect_data(const std::string& redirect_data) {
-    redirect_data_ = redirect_data;
-  }
-
-  void set_cancel_redirect_request(bool cancel_redirect_request) {
-    cancel_redirect_request_ = cancel_redirect_request;
-  }
-
-  void set_intercept_final_response(bool intercept_final_response) {
-    intercept_final_response_ = intercept_final_response;
-  }
-
-  void set_final_headers(const std::string& final_headers) {
-    final_headers_ = final_headers;
-  }
-
-  void set_final_data(const std::string& final_data) {
-    final_data_ = final_data;
-  }
-
-  void set_cancel_final_request(bool cancel_final_request) {
-    cancel_final_request_ = cancel_final_request;
-  }
-
-  void set_use_url_request_http_job(bool use_url_request_http_job) {
-    use_url_request_http_job_ = use_url_request_http_job;
-  }
-
-  bool did_intercept_main() const {
-    return did_intercept_main_;
-  }
-
-  bool did_restart_main() const {
-    return did_restart_main_;
-  }
-
-  bool did_cancel_main() const {
-    return did_cancel_main_;
-  }
-
-  bool did_cancel_then_restart_main() const {
-    return did_cancel_then_restart_main_;
-  }
-
-  bool did_simulate_error_main() const {
-    return did_simulate_error_main_;
-  }
-
-  bool did_intercept_redirect() const {
-    return did_intercept_redirect_;
-  }
-
-  bool did_cancel_redirect() const {
-    return did_cancel_redirect_;
-  }
-
-  bool did_intercept_final() const {
-    return did_intercept_final_;
-  }
-
-  bool did_cancel_final() const {
-    return did_cancel_final_;
-  }
-
  private:
-  // Indicate whether to intercept the main request, and if so specify the
-  // response to return and the LoadTimingInfo to use.
-  mutable bool intercept_main_request_;
-  mutable std::string main_headers_;
-  mutable std::string main_data_;
   mutable LoadTimingInfo main_request_load_timing_info_;
-
-  // These indicate actions that can be taken within MaybeInterceptRequest.
-  mutable bool restart_main_request_;
-  mutable bool cancel_main_request_;
-  mutable bool cancel_then_restart_main_request_;
-  mutable bool simulate_main_network_error_;
-
-  // Indicate whether to intercept redirects, and if so specify the response to
-  // return.
-  mutable bool intercept_redirect_;
-  mutable std::string redirect_headers_;
-  mutable std::string redirect_data_;
-
-  // Cancel the request within MaybeInterceptRedirect.
-  mutable bool cancel_redirect_request_;
-
-  // Indicate whether to intercept the final response, and if so specify the
-  // response to return.
-  mutable bool intercept_final_response_;
-  mutable std::string final_headers_;
-  mutable std::string final_data_;
-
-  // Cancel the final request within MaybeInterceptResponse.
-  mutable bool cancel_final_request_;
-
-  // Instruct the interceptor to use a real URLRequestHTTPJob.
-  mutable bool use_url_request_http_job_;
-
-  // These indicate if the interceptor did something or not.
-  mutable bool did_intercept_main_;
-  mutable bool did_restart_main_;
-  mutable bool did_cancel_main_;
-  mutable bool did_cancel_then_restart_main_;
-  mutable bool did_simulate_error_main_;
-  mutable bool did_intercept_redirect_;
-  mutable bool did_cancel_redirect_;
-  mutable bool did_intercept_final_;
-  mutable bool did_cancel_final_;
 };
 
 // Inherit PlatformTest since we require the autorelease pool on Mac OS X.
@@ -1272,9 +988,6 @@
 
 TEST_F(URLRequestInterceptorTest, Intercept) {
   // Intercept the main request and respond with a simple response.
-  interceptor()->set_intercept_main_request(true);
-  interceptor()->set_main_headers(MockURLRequestInterceptor::ok_headers());
-  interceptor()->set_main_data(MockURLRequestInterceptor::ok_data());
   TestDelegate d;
   std::unique_ptr<URLRequest> req(default_context().CreateRequest(
       GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d,
@@ -1302,238 +1015,6 @@
   EXPECT_EQ(0, d.received_redirect_count());
 }
 
-TEST_F(URLRequestInterceptorTest, InterceptRedirect) {
-  // Intercept the main request and respond with a redirect.
-  interceptor()->set_intercept_main_request(true);
-  interceptor()->set_main_headers(
-      MockURLRequestInterceptor::redirect_headers());
-  interceptor()->set_main_data(MockURLRequestInterceptor::redirect_data());
-
-  // Intercept that redirect and respond with a final OK response.
-  interceptor()->set_intercept_redirect(true);
-  interceptor()->set_redirect_headers(MockURLRequestInterceptor::ok_headers());
-  interceptor()->set_redirect_data(MockURLRequestInterceptor::ok_data());
-
-  TestDelegate d;
-  std::unique_ptr<URLRequest> req(default_context().CreateRequest(
-      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d,
-      TRAFFIC_ANNOTATION_FOR_TESTS));
-  req->set_method("GET");
-  req->Start();
-  d.RunUntilComplete();
-
-  // Check that the interceptor got called as expected.
-  EXPECT_TRUE(interceptor()->did_intercept_main());
-  EXPECT_TRUE(interceptor()->did_intercept_redirect());
-
-  // Check that we got one good response.
-  int status = d.request_status();
-  EXPECT_EQ(OK, status);
-  if (status == OK)
-    EXPECT_EQ(200, req->response_headers()->response_code());
-
-  EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
-  EXPECT_EQ(1, d.response_started_count());
-  EXPECT_EQ(0, d.received_redirect_count());
-}
-
-TEST_F(URLRequestInterceptorTest, InterceptServerError) {
-  // Intercept the main request to generate a server error response.
-  interceptor()->set_intercept_main_request(true);
-  interceptor()->set_main_headers(MockURLRequestInterceptor::error_headers());
-  interceptor()->set_main_data(MockURLRequestInterceptor::error_data());
-
-  // Intercept that error and respond with an OK response.
-  interceptor()->set_intercept_final_response(true);
-  interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
-  interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
-
-  TestDelegate d;
-  std::unique_ptr<URLRequest> req(default_context().CreateRequest(
-      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d,
-      TRAFFIC_ANNOTATION_FOR_TESTS));
-  req->set_method("GET");
-  req->Start();
-  d.RunUntilComplete();
-
-  // Check that the interceptor got called as expected.
-  EXPECT_TRUE(interceptor()->did_intercept_main());
-  EXPECT_TRUE(interceptor()->did_intercept_final());
-
-  // Check that we got one good response.
-  EXPECT_EQ(OK, d.request_status());
-  EXPECT_EQ(200, req->response_headers()->response_code());
-  EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
-  EXPECT_EQ(1, d.response_started_count());
-  EXPECT_EQ(0, d.received_redirect_count());
-}
-
-TEST_F(URLRequestInterceptorTest, InterceptNetworkError) {
-  // Intercept the main request to simulate a network error.
-  interceptor()->set_simulate_main_network_error(true);
-
-  // Intercept that error and respond with an OK response.
-  interceptor()->set_intercept_final_response(true);
-  interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
-  interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
-
-  TestDelegate d;
-  std::unique_ptr<URLRequest> req(default_context().CreateRequest(
-      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d,
-      TRAFFIC_ANNOTATION_FOR_TESTS));
-  req->set_method("GET");
-  req->Start();
-  d.RunUntilComplete();
-
-  // Check that the interceptor got called as expected.
-  EXPECT_TRUE(interceptor()->did_simulate_error_main());
-  EXPECT_TRUE(interceptor()->did_intercept_final());
-
-  // Check that we received one good response.
-  EXPECT_EQ(OK, d.request_status());
-  EXPECT_EQ(200, req->response_headers()->response_code());
-  EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
-  EXPECT_EQ(1, d.response_started_count());
-  EXPECT_EQ(0, d.received_redirect_count());
-}
-
-TEST_F(URLRequestInterceptorTest, InterceptRestartRequired) {
-  // Restart the main request.
-  interceptor()->set_restart_main_request(true);
-
-  // then intercept the new main request and respond with an OK response
-  interceptor()->set_intercept_main_request(true);
-  interceptor()->set_main_headers(MockURLRequestInterceptor::ok_headers());
-  interceptor()->set_main_data(MockURLRequestInterceptor::ok_data());
-
-  TestDelegate d;
-  std::unique_ptr<URLRequest> req(default_context().CreateRequest(
-      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d,
-      TRAFFIC_ANNOTATION_FOR_TESTS));
-  req->set_method("GET");
-  req->Start();
-  d.RunUntilComplete();
-
-  // Check that the interceptor got called as expected.
-  EXPECT_TRUE(interceptor()->did_restart_main());
-  EXPECT_TRUE(interceptor()->did_intercept_main());
-
-  // Check that we received one good response.
-  int status = d.request_status();
-  EXPECT_EQ(OK, status);
-  if (status == OK)
-    EXPECT_EQ(200, req->response_headers()->response_code());
-
-  EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
-  EXPECT_EQ(1, d.response_started_count());
-  EXPECT_EQ(0, d.received_redirect_count());
-}
-
-TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelMain) {
-  // Intercept the main request and cancel from within the restarted job.
-  interceptor()->set_cancel_main_request(true);
-
-  // Set up to intercept the final response and override it with an OK response.
-  interceptor()->set_intercept_final_response(true);
-  interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
-  interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
-
-  TestDelegate d;
-  std::unique_ptr<URLRequest> req(default_context().CreateRequest(
-      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d,
-      TRAFFIC_ANNOTATION_FOR_TESTS));
-  req->set_method("GET");
-  req->Start();
-  d.RunUntilComplete();
-
-  // Check that the interceptor got called as expected.
-  EXPECT_TRUE(interceptor()->did_cancel_main());
-  EXPECT_FALSE(interceptor()->did_intercept_final());
-
-  // Check that we see a canceled request.
-  EXPECT_EQ(ERR_ABORTED, d.request_status());
-}
-
-TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelRedirect) {
-  // Intercept the main request and respond with a redirect.
-  interceptor()->set_intercept_main_request(true);
-  interceptor()->set_main_headers(
-      MockURLRequestInterceptor::redirect_headers());
-  interceptor()->set_main_data(MockURLRequestInterceptor::redirect_data());
-
-  // Intercept the redirect and cancel from within that job.
-  interceptor()->set_cancel_redirect_request(true);
-
-  // Set up to intercept the final response and override it with an OK response.
-  interceptor()->set_intercept_final_response(true);
-  interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
-  interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
-
-  TestDelegate d;
-  std::unique_ptr<URLRequest> req(default_context().CreateRequest(
-      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d,
-      TRAFFIC_ANNOTATION_FOR_TESTS));
-  req->set_method("GET");
-  req->Start();
-  d.RunUntilComplete();
-
-  // Check that the interceptor got called as expected.
-  EXPECT_TRUE(interceptor()->did_intercept_main());
-  EXPECT_TRUE(interceptor()->did_cancel_redirect());
-  EXPECT_FALSE(interceptor()->did_intercept_final());
-
-  // Check that we see a canceled request.
-  EXPECT_EQ(ERR_ABORTED, d.request_status());
-}
-
-TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelFinal) {
-  // Intercept the main request to simulate a network error.
-  interceptor()->set_simulate_main_network_error(true);
-
-  // Set up to intercept final the response and cancel from within that job.
-  interceptor()->set_cancel_final_request(true);
-
-  TestDelegate d;
-  std::unique_ptr<URLRequest> req(default_context().CreateRequest(
-      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d,
-      TRAFFIC_ANNOTATION_FOR_TESTS));
-  req->set_method("GET");
-  req->Start();
-  d.RunUntilComplete();
-
-  // Check that the interceptor got called as expected.
-  EXPECT_TRUE(interceptor()->did_simulate_error_main());
-  EXPECT_TRUE(interceptor()->did_cancel_final());
-
-  // Check that we see a canceled request.
-  EXPECT_EQ(ERR_ABORTED, d.request_status());
-}
-
-TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelInRestart) {
-  // Intercept the main request and cancel then restart from within that job.
-  interceptor()->set_cancel_then_restart_main_request(true);
-
-  // Set up to intercept the final response and override it with an OK response.
-  interceptor()->set_intercept_final_response(true);
-  interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
-  interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
-
-  TestDelegate d;
-  std::unique_ptr<URLRequest> req(default_context().CreateRequest(
-      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d,
-      TRAFFIC_ANNOTATION_FOR_TESTS));
-  req->set_method("GET");
-  req->Start();
-  d.RunUntilComplete();
-
-  // Check that the interceptor got called as expected.
-  EXPECT_TRUE(interceptor()->did_cancel_then_restart_main());
-  EXPECT_FALSE(interceptor()->did_intercept_final());
-
-  // Check that we see a canceled request.
-  EXPECT_EQ(ERR_ABORTED, d.request_status());
-}
-
 // "Normal" LoadTimingInfo as returned by a job.  Everything is in order, not
 // reused.  |connect_time_flags| is used to indicate if there should be dns
 // or SSL times, and |used_proxy| is used for proxy times.
@@ -1590,7 +1071,6 @@
     const LoadTimingInfo& job_load_timing,
     const URLRequestContext& context,
     MockURLRequestInterceptor* interceptor) {
-  interceptor->set_intercept_main_request(true);
   interceptor->set_main_request_load_timing_info(job_load_timing);
   TestDelegate d;
   std::unique_ptr<URLRequest> req(
@@ -9104,105 +8584,6 @@
   MockURLRequestInterceptor* interceptor_;
 };
 
-TEST_F(URLRequestInterceptorTestHTTP,
-       NetworkDelegateNotificationOnRedirectIntercept) {
-  interceptor()->set_intercept_redirect(true);
-  interceptor()->set_redirect_headers(MockURLRequestInterceptor::ok_headers());
-  interceptor()->set_redirect_data(MockURLRequestInterceptor::ok_data());
-
-  ASSERT_TRUE(http_test_server()->Start());
-
-  TestDelegate d;
-  std::unique_ptr<URLRequest> req(default_context().CreateRequest(
-      http_test_server()->GetURL("/redirect-test.html"), DEFAULT_PRIORITY, &d,
-      TRAFFIC_ANNOTATION_FOR_TESTS));
-  req->Start();
-  d.RunUntilComplete();
-
-  EXPECT_TRUE(interceptor()->did_intercept_redirect());
-  // Check we got one good response
-  int status = d.request_status();
-  EXPECT_EQ(OK, status);
-  if (status == OK)
-    EXPECT_EQ(200, req->response_headers()->response_code());
-
-  EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
-  EXPECT_EQ(1, d.response_started_count());
-  EXPECT_EQ(0, d.received_redirect_count());
-
-  EXPECT_EQ(1, default_network_delegate()->created_requests());
-  EXPECT_EQ(1, default_network_delegate()->before_start_transaction_count());
-  EXPECT_EQ(1, default_network_delegate()->headers_received_count());
-}
-
-TEST_F(URLRequestInterceptorTestHTTP,
-       NetworkDelegateNotificationOnErrorIntercept) {
-  // Intercept that error and respond with an OK response.
-  interceptor()->set_intercept_final_response(true);
-  interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
-  interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
-  default_network_delegate()->set_can_be_intercepted_on_error(true);
-
-  ASSERT_TRUE(http_test_server()->Start());
-
-  TestDelegate d;
-  std::unique_ptr<URLRequest> req(default_context().CreateRequest(
-      http_test_server()->GetURL("/two-content-lengths.html"), DEFAULT_PRIORITY,
-      &d, TRAFFIC_ANNOTATION_FOR_TESTS));
-  req->set_method("GET");
-  req->Start();
-  d.RunUntilComplete();
-
-  EXPECT_TRUE(interceptor()->did_intercept_final());
-
-  // Check we received one good response.
-  int status = d.request_status();
-  EXPECT_EQ(OK, status);
-  if (status == OK)
-    EXPECT_EQ(200, req->response_headers()->response_code());
-  EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
-  EXPECT_EQ(1, d.response_started_count());
-  EXPECT_EQ(0, d.received_redirect_count());
-
-  EXPECT_EQ(1, default_network_delegate()->created_requests());
-  EXPECT_EQ(1, default_network_delegate()->before_start_transaction_count());
-  EXPECT_EQ(0, default_network_delegate()->headers_received_count());
-}
-
-TEST_F(URLRequestInterceptorTestHTTP,
-       NetworkDelegateNotificationOnResponseIntercept) {
-  // Intercept that error and respond with an OK response.
-  interceptor()->set_intercept_final_response(true);
-
-  // Intercept with a real URLRequestHttpJob.
-  interceptor()->set_use_url_request_http_job(true);
-
-  ASSERT_TRUE(http_test_server()->Start());
-
-  TestDelegate d;
-  std::unique_ptr<URLRequest> req(default_context().CreateRequest(
-      http_test_server()->GetURL("/simple.html"), DEFAULT_PRIORITY, &d,
-      TRAFFIC_ANNOTATION_FOR_TESTS));
-  req->set_method("GET");
-  req->Start();
-  d.RunUntilComplete();
-
-  EXPECT_TRUE(interceptor()->did_intercept_final());
-
-  // Check we received one good response.
-  int status = d.request_status();
-  EXPECT_EQ(OK, status);
-  if (status == OK)
-    EXPECT_EQ(200, req->response_headers()->response_code());
-  EXPECT_EQ("hello", d.data_received());
-  EXPECT_EQ(1, d.response_started_count());
-  EXPECT_EQ(0, d.received_redirect_count());
-
-  EXPECT_EQ(1, default_network_delegate()->created_requests());
-  EXPECT_EQ(2, default_network_delegate()->before_start_transaction_count());
-  EXPECT_EQ(2, default_network_delegate()->headers_received_count());
-}
-
 class URLRequestTestReferrerPolicy : public URLRequestTest {
  public:
   URLRequestTestReferrerPolicy() = default;
diff --git a/pdf/pdfium/accessibility_unittest.cc b/pdf/pdfium/accessibility_unittest.cc
index 3add565..f1f59f6 100644
--- a/pdf/pdfium/accessibility_unittest.cc
+++ b/pdf/pdfium/accessibility_unittest.cc
@@ -7,6 +7,7 @@
 #include "pdf/pdfium/pdfium_engine.h"
 #include "pdf/pdfium/pdfium_test_base.h"
 #include "pdf/test/test_client.h"
+#include "pdf/test/test_utils.h"
 #include "ppapi/c/private/ppb_pdf.h"
 #include "ppapi/c/private/ppp_pdf.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -172,21 +173,140 @@
   // This test checks that accessibility scroll action is passed
   // on to the ScrollEnabledTestClient implementation.
   ScrollEnabledTestClient client;
-  std::unique_ptr<PDFiumEngine> engine =
-      InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
+  std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
+      &client, FILE_PATH_LITERAL("rectangles_multi_pages.pdf"));
   ASSERT_TRUE(engine);
+  engine->PluginSizeUpdated({400, 400});
   PP_PdfAccessibilityActionData action_data;
   action_data.action = PP_PdfAccessibilityAction::PP_PDF_SCROLL_TO_MAKE_VISIBLE;
   action_data.target_rect = {{120, 0}, {10, 10}};
-  // As Pdfium::Client is mocked, we will receive the same points back.
-  engine->HandleAccessibilityAction(action_data);
-  EXPECT_EQ(action_data.target_rect.point, client.GetScrollRequestPoints());
 
-  // Simulate a zoom update in the PDFiumEngine.
-  engine->ZoomUpdated(1.5);
+  // Horizontal and Vertical scroll alignment of none should not scroll.
+  action_data.horizontal_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_NONE;
+  action_data.vertical_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_NONE;
   engine->HandleAccessibilityAction(action_data);
-  constexpr PP_Point kExpectedPoint = {180, 0};
-  EXPECT_EQ(kExpectedPoint, client.GetScrollRequestPoints());
+  ComparePoint({0, 0}, client.GetScrollRequestPoints());
+
+  action_data.horizontal_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_LEFT;
+  action_data.vertical_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_TOP;
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({120, 0}, client.GetScrollRequestPoints());
+
+  action_data.horizontal_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_LEFT;
+  action_data.vertical_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_BOTTOM;
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({120, -400}, client.GetScrollRequestPoints());
+
+  action_data.horizontal_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_RIGHT;
+  action_data.vertical_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_TOP;
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({-280, 0}, client.GetScrollRequestPoints());
+
+  action_data.horizontal_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_RIGHT;
+  action_data.vertical_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_BOTTOM;
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({-280, -400}, client.GetScrollRequestPoints());
+
+  action_data.horizontal_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_CENTER;
+  action_data.vertical_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_CENTER;
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({-80, -200}, client.GetScrollRequestPoints());
+
+  // Simulate a 150% zoom update in the PDFiumEngine.
+  engine->PluginSizeUpdated({600, 600});
+
+  action_data.horizontal_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_NONE;
+  action_data.vertical_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_NONE;
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({0, 0}, client.GetScrollRequestPoints());
+
+  action_data.horizontal_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_LEFT;
+  action_data.vertical_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_TOP;
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({120, 0}, client.GetScrollRequestPoints());
+
+  action_data.horizontal_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_LEFT;
+  action_data.vertical_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_BOTTOM;
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({120, -600}, client.GetScrollRequestPoints());
+
+  action_data.horizontal_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_RIGHT;
+  action_data.vertical_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_TOP;
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({-480, 0}, client.GetScrollRequestPoints());
+
+  action_data.horizontal_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_RIGHT;
+  action_data.vertical_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_BOTTOM;
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({-480, -600}, client.GetScrollRequestPoints());
+
+  action_data.horizontal_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_CENTER;
+  action_data.vertical_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_CENTER;
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({-180, -300}, client.GetScrollRequestPoints());
+}
+
+TEST_F(AccessibilityTest, TestScrollToNearestEdge) {
+  ScrollEnabledTestClient client;
+  std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
+      &client, FILE_PATH_LITERAL("rectangles_multi_pages.pdf"));
+  ASSERT_TRUE(engine);
+  engine->PluginSizeUpdated({400, 400});
+  PP_PdfAccessibilityActionData action_data;
+  action_data.action = PP_PdfAccessibilityAction::PP_PDF_SCROLL_TO_MAKE_VISIBLE;
+
+  action_data.horizontal_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_CLOSEST_EDGE;
+  action_data.vertical_scroll_alignment =
+      PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_CLOSEST_EDGE;
+  // Point which is in the middle of the viewport.
+  action_data.target_rect = {{200, 200}, {10, 10}};
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({200, 200}, client.GetScrollRequestPoints());
+
+  // Point which is near the top left of the viewport.
+  action_data.target_rect = {{199, 199}, {10, 10}};
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({199, 199}, client.GetScrollRequestPoints());
+
+  // Point which is near the top right of the viewport
+  action_data.target_rect = {{201, 199}, {10, 10}};
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({-199, 199}, client.GetScrollRequestPoints());
+
+  // Point which is near the bottom left of the viewport.
+  action_data.target_rect = {{199, 201}, {10, 10}};
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({199, -199}, client.GetScrollRequestPoints());
+
+  // Point which is near the bottom right of the viewport
+  action_data.target_rect = {{201, 201}, {10, 10}};
+  engine->HandleAccessibilityAction(action_data);
+  ComparePoint({-199, -199}, client.GetScrollRequestPoints());
 }
 
 // This class is required to just override the NavigateTo
@@ -203,15 +323,24 @@
     disposition_ = disposition;
   }
 
+  void ScrollToY(int y_in_screen_coords, bool compensate_for_toolbar) override {
+    y_scroll_offset_ = y_in_screen_coords;
+    compensate_for_toolbar_ = compensate_for_toolbar;
+  }
+
   const std::string& url() const { return url_; }
   WindowOpenDisposition disposition() const { return disposition_; }
+  int y_scroll_offset() const { return y_scroll_offset_; }
+  bool compensate_for_toolbar() const { return compensate_for_toolbar_; }
 
  private:
   std::string url_;
-  WindowOpenDisposition disposition_;
+  WindowOpenDisposition disposition_ = WindowOpenDisposition::UNKNOWN;
+  int y_scroll_offset_ = 0;
+  bool compensate_for_toolbar_ = false;
 };
 
-TEST_F(AccessibilityTest, TestLinkDefaultActionHandling) {
+TEST_F(AccessibilityTest, TestWebLinkClickActionHandling) {
   NavigationEnabledTestClient client;
   std::unique_ptr<PDFiumEngine> engine =
       InitializeEngine(&client, FILE_PATH_LITERAL("weblinks.pdf"));
@@ -226,4 +355,20 @@
   EXPECT_EQ(WindowOpenDisposition::CURRENT_TAB, client.disposition());
 }
 
+TEST_F(AccessibilityTest, TestInternalLinkClickActionHandling) {
+  NavigationEnabledTestClient client;
+  std::unique_ptr<PDFiumEngine> engine =
+      InitializeEngine(&client, FILE_PATH_LITERAL("link_annots.pdf"));
+  ASSERT_TRUE(engine);
+
+  PP_PdfAccessibilityActionData action_data;
+  action_data.action = PP_PdfAccessibilityAction::PP_PDF_DO_DEFAULT_ACTION;
+  action_data.page_index = 0;
+  action_data.link_index = 1;
+  engine->HandleAccessibilityAction(action_data);
+  EXPECT_EQ(1159, client.y_scroll_offset());
+  EXPECT_TRUE(client.compensate_for_toolbar());
+  EXPECT_TRUE(client.url().empty());
+}
+
 }  // namespace chrome_pdf
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 2019d74..ee8a40d 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -37,7 +37,6 @@
 #include "pdf/pdfium/pdfium_permissions.h"
 #include "pdf/pdfium/pdfium_unsupported_features.h"
 #include "pdf/url_loader_wrapper_impl.h"
-#include "ppapi/c/private/ppp_pdf.h"
 #include "ppapi/cpp/instance.h"
 #include "ppapi/cpp/private/pdf.h"
 #include "ppapi/cpp/var_dictionary.h"
@@ -1986,11 +1985,11 @@
     const PP_PdfAccessibilityActionData& action_data) {
   switch (action_data.action) {
     case PP_PdfAccessibilityAction::PP_PDF_SCROLL_TO_MAKE_VISIBLE: {
-      pp::Rect target_rect =
-          pp::Rect(action_data.target_rect.point, action_data.target_rect.size);
-      pp::Rect target_point_screen = GetScreenRect(target_rect);
-      client_->ScrollBy(target_point_screen.point());
-    } break;
+      ScrollBasedOnScrollAlignment(action_data.target_rect,
+                                   action_data.horizontal_scroll_alignment,
+                                   action_data.vertical_scroll_alignment);
+      break;
+    }
     case PP_PdfAccessibilityAction::PP_PDF_DO_DEFAULT_ACTION: {
       if (PageIndexInBounds(action_data.page_index)) {
         PDFiumPage::LinkTarget target;
@@ -2000,7 +1999,8 @@
         NavigateToLinkDestination(area, target,
                                   WindowOpenDisposition::CURRENT_TAB);
       }
-    } break;
+      break;
+    }
     default:
       NOTREACHED();
       break;
@@ -2112,6 +2112,62 @@
   return dict;
 }
 
+void PDFiumEngine::ScrollBasedOnScrollAlignment(
+    const pp::Rect& scroll_rect,
+    const PP_PdfAccessibilityScrollAlignment& horizontal_scroll_alignment,
+    const PP_PdfAccessibilityScrollAlignment& vertical_scroll_alignment) {
+  pp::Point scroll_offset = GetScreenRect(scroll_rect).point();
+  switch (horizontal_scroll_alignment) {
+    case PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_RIGHT:
+      scroll_offset.set_x(scroll_offset.x() - plugin_size_.width());
+      break;
+    case PP_PDF_SCROLL_ALIGNMENT_CENTER:
+      scroll_offset.set_x(scroll_offset.x() - (plugin_size_.width() / 2));
+      break;
+    case PP_PDF_SCROLL_ALIGNMENT_CLOSEST_EDGE: {
+      scroll_offset.set_x((std::abs(scroll_offset.x()) <=
+                           std::abs(scroll_offset.x() - plugin_size_.width()))
+                              ? scroll_offset.x()
+                              : scroll_offset.x() - plugin_size_.width());
+      break;
+    }
+    case PP_PDF_SCROLL_NONE:
+      scroll_offset.set_x(0);
+      break;
+    case PP_PDF_SCROLL_ALIGNMENT_LEFT:
+    case PP_PDF_SCROLL_ALIGNMENT_TOP:
+    case PP_PDF_SCROLL_ALIGNMENT_BOTTOM:
+    default:
+      break;
+  }
+
+  switch (vertical_scroll_alignment) {
+    case PP_PDF_SCROLL_ALIGNMENT_BOTTOM:
+      scroll_offset.set_y(scroll_offset.y() - plugin_size_.height());
+      break;
+    case PP_PDF_SCROLL_ALIGNMENT_CENTER:
+      scroll_offset.set_y(scroll_offset.y() - (plugin_size_.height() / 2));
+      break;
+    case PP_PDF_SCROLL_ALIGNMENT_CLOSEST_EDGE: {
+      scroll_offset.set_y((std::abs(scroll_offset.y()) <=
+                           std::abs(scroll_offset.y() - plugin_size_.height()))
+                              ? scroll_offset.y()
+                              : scroll_offset.y() - plugin_size_.height());
+      break;
+    }
+    case PP_PDF_SCROLL_NONE:
+      scroll_offset.set_y(0);
+      break;
+    case PP_PDF_SCROLL_ALIGNMENT_TOP:
+    case PP_PDF_SCROLL_ALIGNMENT_LEFT:
+    case PP_PDF_SCROLL_ALIGNMENT_RIGHT:
+    default:
+      break;
+  }
+
+  client_->ScrollBy(scroll_offset);
+}
+
 base::Optional<PDFEngine::NamedDestination> PDFiumEngine::GetNamedDestination(
     const std::string& destination) {
   // Look for the destination.
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index d945f90f..e062378e7 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -24,6 +24,7 @@
 #include "pdf/pdfium/pdfium_page.h"
 #include "pdf/pdfium/pdfium_print.h"
 #include "pdf/pdfium/pdfium_range.h"
+#include "ppapi/c/private/ppp_pdf.h"
 #include "ppapi/cpp/completion_callback.h"
 #include "ppapi/cpp/dev/buffer_dev.h"
 #include "ppapi/cpp/image_data.h"
@@ -513,6 +514,11 @@
   pp::VarDictionary TraverseBookmarks(FPDF_BOOKMARK bookmark,
                                       unsigned int depth);
 
+  void ScrollBasedOnScrollAlignment(
+      const pp::Rect& scroll_rect,
+      const PP_PdfAccessibilityScrollAlignment& horizontal_scroll_alignment,
+      const PP_PdfAccessibilityScrollAlignment& vertical_scroll_alignment);
+
   // Set if the document has any local edits.
   void SetEditMode(bool edit_mode);
 
diff --git a/pdf/pdfium/pdfium_page.cc b/pdf/pdfium/pdfium_page.cc
index 9ba35beb..320732f 100644
--- a/pdf/pdfium/pdfium_page.cc
+++ b/pdf/pdfium/pdfium_page.cc
@@ -439,9 +439,8 @@
   CalculateLinks();
   if (link_index >= static_cast<int>(links_.size()))
     return NONSELECTABLE_AREA;
-  target->url = links_[link_index].target.url;
-  DCHECK(!target->url.empty());
-  return WEBLINK_AREA;
+  *target = links_[link_index].target;
+  return target->url.empty() ? DOCLINK_AREA : WEBLINK_AREA;
 }
 
 PDFiumPage::Area PDFiumPage::GetCharIndex(const pp::Point& point,
diff --git a/pdf/test/test_utils.cc b/pdf/test/test_utils.cc
index 4057169..e58e5e1d 100644
--- a/pdf/test/test_utils.cc
+++ b/pdf/test/test_utils.cc
@@ -4,11 +4,18 @@
 
 #include "pdf/test/test_utils.h"
 
+#include "ppapi/cpp/point.h"
 #include "ppapi/cpp/rect.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chrome_pdf {
 
+void ComparePoint(const pp::Point& expected_point,
+                  const pp::Point& given_point) {
+  EXPECT_EQ(expected_point.x(), given_point.x());
+  EXPECT_EQ(expected_point.y(), given_point.y());
+}
+
 void CompareRect(const pp::Rect& expected_rect, const pp::Rect& given_rect) {
   EXPECT_EQ(expected_rect.x(), given_rect.x());
   EXPECT_EQ(expected_rect.y(), given_rect.y());
diff --git a/pdf/test/test_utils.h b/pdf/test/test_utils.h
index fb05d06ad..d336dfd 100644
--- a/pdf/test/test_utils.h
+++ b/pdf/test/test_utils.h
@@ -7,12 +7,15 @@
 
 namespace pp {
 class FloatRect;
+class Point;
 class Rect;
 class Size;
 }  // namespace pp
 
 namespace chrome_pdf {
 
+void ComparePoint(const pp::Point& expected_point,
+                  const pp::Point& given_point);
 void CompareRect(const pp::Rect& expected_rect, const pp::Rect& given_rect);
 void CompareRect(const pp::FloatRect& expected_rect,
                  const pp::FloatRect& given_rect);
diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn
index 63864dc..a6fbc30f 100644
--- a/sandbox/win/BUILD.gn
+++ b/sandbox/win/BUILD.gn
@@ -94,6 +94,8 @@
     "src/restricted_token_utils.h",
     "src/sandbox.cc",
     "src/sandbox.h",
+    "src/sandbox_constants.cc",
+    "src/sandbox_constants.h",
     "src/sandbox_factory.h",
     "src/sandbox_globals.cc",
     "src/sandbox_nt_types.h",
@@ -102,6 +104,8 @@
     "src/sandbox_policy.h",
     "src/sandbox_policy_base.cc",
     "src/sandbox_policy_base.h",
+    "src/sandbox_policy_info.cc",
+    "src/sandbox_policy_info.h",
     "src/sandbox_rand.cc",
     "src/sandbox_rand.h",
     "src/sandbox_types.h",
diff --git a/sandbox/win/src/broker_services.cc b/sandbox/win/src/broker_services.cc
index b4eb536eb..a36d569 100644
--- a/sandbox/win/src/broker_services.cc
+++ b/sandbox/win/src/broker_services.cc
@@ -53,6 +53,7 @@
   THREAD_CTRL_NEW_JOB_TRACKER,
   THREAD_CTRL_NEW_PROCESS_TRACKER,
   THREAD_CTRL_PROCESS_SIGNALLED,
+  THREAD_CTRL_GET_POLICY_INFO,
   THREAD_CTRL_QUIT,
   THREAD_CTRL_LAST,
 };
@@ -116,11 +117,11 @@
   }
 }
 
-// Helper redispatches to process events to tracker thread
+// Helper redispatches process events to tracker thread.
 void WINAPI ProcessEventCallback(PVOID param, BOOLEAN ignored) {
-  // This callback should do very little, and must be threadpool safe
+  // This callback should do very little, and must be threadpool safe.
   ProcessTracker* tracker = reinterpret_cast<ProcessTracker*>(param);
-  // if this fails we can do nothing... we will leak the policy.
+  // If this fails we can do nothing... we will leak the policy.
   ::PostQueuedCompletionStatus(tracker->iocp, 0, THREAD_CTRL_PROCESS_SIGNALLED,
                                reinterpret_cast<LPOVERLAPPED>(tracker));
 }
@@ -328,6 +329,28 @@
             return p->process_id == tracker->process_id;
           }));
 
+    } else if (THREAD_CTRL_GET_POLICY_INFO == key) {
+      // Clone the policies for sandbox diagnostics.
+      std::unique_ptr<PolicyDiagnosticsReceiver> receiver;
+      receiver.reset(static_cast<PolicyDiagnosticsReceiver*>(
+          reinterpret_cast<void*>(ovl)));
+      // The PollicyInfo ctor copies essential information from the trackers.
+      auto policy_list = std::make_unique<PolicyList>();
+      for (auto&& process_tracker : processes) {
+        if (process_tracker->policy) {
+          policy_list->push_back(
+              std::make_unique<PolicyInfo>(process_tracker->policy.get()));
+        }
+      }
+      for (auto&& job_tracker : jobs) {
+        if (job_tracker->policy) {
+          policy_list->push_back(
+              std::make_unique<PolicyInfo>(job_tracker->policy.get()));
+        }
+      }
+      // Receiver should return quickly.
+      receiver->ReceiveDiagnostics(std::move(policy_list));
+
     } else if (THREAD_CTRL_QUIT == key) {
       // The broker object is being destroyed so the thread needs to exit.
       for (auto&& tracker : processes) {
@@ -615,4 +638,20 @@
   return SBOX_ALL_OK;
 }
 
+ResultCode BrokerServicesBase::GetPolicyDiagnostics(
+    std::unique_ptr<PolicyDiagnosticsReceiver> receiver) {
+  CHECK(job_thread_.IsValid());
+  // Post to the job thread.
+  if (!::PostQueuedCompletionStatus(
+          job_port_.Get(), 0, THREAD_CTRL_GET_POLICY_INFO,
+          reinterpret_cast<LPOVERLAPPED>(receiver.get()))) {
+    receiver->OnError(SBOX_ERROR_GENERIC);
+    return SBOX_ERROR_GENERIC;
+  }
+
+  // Ownership has passed to tracker thread.
+  receiver.release();
+  return SBOX_ALL_OK;
+}
+
 }  // namespace sandbox
diff --git a/sandbox/win/src/broker_services.h b/sandbox/win/src/broker_services.h
index fc26b62c..360d9f7 100644
--- a/sandbox/win/src/broker_services.h
+++ b/sandbox/win/src/broker_services.h
@@ -18,6 +18,7 @@
 #include "sandbox/win/src/crosscall_server.h"
 #include "sandbox/win/src/job.h"
 #include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_policy_info.h"
 #include "sandbox/win/src/sharedmem_ipc_server.h"
 #include "sandbox/win/src/win2k_threadpool.h"
 #include "sandbox/win/src/win_utils.h"
@@ -48,6 +49,8 @@
                          DWORD* last_error,
                          PROCESS_INFORMATION* target) override;
   ResultCode WaitForAllTargets() override;
+  ResultCode GetPolicyDiagnostics(
+      std::unique_ptr<PolicyDiagnosticsReceiver> receiver) override;
 
  private:
   // The routine that the worker thread executes. It is in charge of
diff --git a/sandbox/win/src/sandbox.h b/sandbox/win/src/sandbox.h
index f8b7c8f..7e9662c2 100644
--- a/sandbox/win/src/sandbox.h
+++ b/sandbox/win/src/sandbox.h
@@ -25,6 +25,10 @@
 #include "sandbox/win/fuzzer/fuzzer_types.h"
 #endif
 
+#include <stddef.h>
+#include <memory>
+#include <vector>
+
 #include "base/memory/ref_counted.h"
 #include "sandbox/win/src/sandbox_policy.h"
 #include "sandbox/win/src/sandbox_types.h"
@@ -33,10 +37,14 @@
 namespace sandbox {
 
 class BrokerServices;
+class PolicyDiagnosticsReceiver;
+class PolicyInfo;
 class ProcessState;
 class TargetPolicy;
 class TargetServices;
 
+using PolicyList = std::vector<std::unique_ptr<PolicyInfo>>;
+
 // BrokerServices exposes all the broker API.
 // The basic use is to start the target(s) and wait for them to end.
 //
@@ -96,6 +104,18 @@
   //   more information.
   virtual ResultCode WaitForAllTargets() = 0;
 
+  // This call creates a snapshot of policies managed by the sandbox and
+  // returns them via a helper class.
+  // Parameters:
+  //   receiver: The |PolicyDiagnosticsReceiver| implementation will be
+  //   called to accept the results of the call.
+  // Returns:
+  //   ALL_OK if the request was dispatched. All other return values
+  //   imply failure, and the responder will not receive its completion
+  //   callback.
+  virtual ResultCode GetPolicyDiagnostics(
+      std::unique_ptr<PolicyDiagnosticsReceiver> receiver) = 0;
+
  protected:
   ~BrokerServices() {}
 };
@@ -145,6 +165,18 @@
   ~TargetServices() {}
 };
 
+// This class mediates calls to BrokerServices::GetPolicyDiagnostics().
+class PolicyDiagnosticsReceiver {
+ public:
+  // ReceiveDiagnostics() should return quickly and should not block the
+  // thread on which it is called.
+  virtual void ReceiveDiagnostics(std::unique_ptr<PolicyList> policies) = 0;
+  // OnError() is passed any errors encountered and |ReceiveDiagnostics|
+  // will not be called.
+  virtual void OnError(ResultCode code) = 0;
+  virtual ~PolicyDiagnosticsReceiver() {}
+};
+
 }  // namespace sandbox
 
 #endif  // SANDBOX_WIN_SRC_SANDBOX_H_
diff --git a/sandbox/win/src/sandbox_constants.cc b/sandbox/win/src/sandbox_constants.cc
new file mode 100644
index 0000000..90c33d3
--- /dev/null
+++ b/sandbox/win/src/sandbox_constants.cc
@@ -0,0 +1,11 @@
+// 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 "sandbox/win/src/sandbox_constants.h"
+
+namespace sandbox {
+// Strings used as keys in base::Value snapshots of Policies.
+extern const char kProcessIds[] = "process_ids";
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sandbox_constants.h b/sandbox/win/src/sandbox_constants.h
new file mode 100644
index 0000000..76d4d91
--- /dev/null
+++ b/sandbox/win/src/sandbox_constants.h
@@ -0,0 +1,14 @@
+// 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 SANDBOX_WIN_SRC_SANDBOX_CONSTANTS_H_
+#define SANDBOX_WIN_SRC_SANDBOX_CONSTANTS_H_
+
+namespace sandbox {
+// Strings used as keys in base::Value snapshots of Policies.
+extern const char kProcessIds[];
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_SANDBOX_CONSTANTS_H_
diff --git a/sandbox/win/src/sandbox_policy_base.h b/sandbox/win/src/sandbox_policy_base.h
index 631f974..0f5e26ac 100644
--- a/sandbox/win/src/sandbox_policy_base.h
+++ b/sandbox/win/src/sandbox_policy_base.h
@@ -32,6 +32,7 @@
 namespace sandbox {
 
 class LowLevelPolicy;
+class PolicyInfo;
 class TargetProcess;
 struct PolicyGlobal;
 
@@ -113,6 +114,8 @@
   const base::HandlesToInheritVector& GetHandlesBeingShared();
 
  private:
+  // Allow PolicyInfo to snapshot PolicyBase for diagnostics.
+  friend class PolicyInfo;
   ~PolicyBase();
 
   // Sets up interceptions for a new target.
diff --git a/sandbox/win/src/sandbox_policy_info.cc b/sandbox/win/src/sandbox_policy_info.cc
new file mode 100644
index 0000000..10360fa8
--- /dev/null
+++ b/sandbox/win/src/sandbox_policy_info.cc
@@ -0,0 +1,50 @@
+// 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 "sandbox/win/src/sandbox_policy_info.h"
+
+#include "base/numerics/safe_conversions.h"
+#include "base/values.h"
+#include "sandbox/win/src/sandbox_constants.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+#include "sandbox/win/src/target_process.h"
+
+namespace sandbox {
+
+namespace {
+
+base::Value ProcessIdList(std::vector<uint32_t>& pids) {
+  base::ListValue results;
+  for (auto pid : pids) {
+    results.GetList().push_back(base::Value(base::strict_cast<double>(pid)));
+  }
+
+  return std::move(results);
+}
+}  // namespace
+
+// We are a friend of PolicyBase so that we can steal its private members
+// quickly in the BrokerServices tracker thread.
+PolicyInfo::PolicyInfo(PolicyBase* policy) {
+  DCHECK(policy);
+  // TODO(crbug/997273) Add more fields once webui plumbing is complete.
+  {
+    AutoLock lock(&policy->lock_);
+    for (auto&& target_process : policy->targets_) {
+      process_ids_.push_back(
+          base::strict_cast<uint32_t>(target_process->ProcessId()));
+    }
+  }
+}
+
+PolicyInfo::~PolicyInfo() {}
+
+base::Value PolicyInfo::GetValue() {
+  // TODO(crbug/997273) Add more fields once webui plumbing is complete.
+  base::DictionaryValue val;
+  val.SetKey(kProcessIds, ProcessIdList(process_ids_));
+  return std::move(val);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sandbox_policy_info.h b/sandbox/win/src/sandbox_policy_info.h
new file mode 100644
index 0000000..b329402
--- /dev/null
+++ b/sandbox/win/src/sandbox_policy_info.h
@@ -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.
+
+#ifndef SANDBOX_WIN_SRC_SANDBOX_POLICY_INFO_H_
+#define SANDBOX_WIN_SRC_SANDBOX_POLICY_INFO_H_
+
+#include <vector>
+
+#include "base/values.h"
+
+namespace sandbox {
+
+class PolicyBase;
+
+// Intended to rhyme with TargetPolicy, may eventually share a common base
+// with a configuration holding class (i.e. this class will extend with dynamic
+// members such as the |process_ids_| list.)
+class PolicyInfo {
+ public:
+  // This should quickly copy what it needs from PolicyBase.
+  PolicyInfo(PolicyBase* policy);
+  ~PolicyInfo();
+
+  base::Value GetValue();
+
+ private:
+  std::vector<uint32_t> process_ids_;
+
+  DISALLOW_COPY_AND_ASSIGN(PolicyInfo);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_SANDBOX_POLICY_INFO_H_
diff --git a/sandbox/win/tests/integration_tests/integration_tests_test.cc b/sandbox/win/tests/integration_tests/integration_tests_test.cc
index 4acadb9..55665f0 100644
--- a/sandbox/win/tests/integration_tests/integration_tests_test.cc
+++ b/sandbox/win/tests/integration_tests/integration_tests_test.cc
@@ -6,14 +6,59 @@
 
 #include <stddef.h>
 
+#include <windows.h>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/unguessable_token.h"
+#include "base/win/scoped_handle.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_policy_info.h"
 #include "sandbox/win/src/target_services.h"
 #include "sandbox/win/tests/common/controller.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace sandbox {
 
+namespace {
+base::string16 NonCollidingName() {
+  auto token = base::UnguessableToken::Create();
+  return base::UTF8ToUTF16(token.ToString().c_str());
+}
+
+struct PolicyDiagnosticsWaiter {
+ public:
+  PolicyDiagnosticsWaiter() {
+    event.Set(::CreateEventW(nullptr, false, false, nullptr));
+    policies = nullptr;
+  }
+
+  base::win::ScopedHandle event;
+  std::unique_ptr<PolicyList> policies;
+
+  std::unique_ptr<PolicyList> WaitForPolicies() {
+    ::WaitForSingleObject(event.Get(), INFINITE);
+    return std::move(policies);
+  }
+};
+
+class TestDiagnosticsReceiver : public PolicyDiagnosticsReceiver {
+ public:
+  TestDiagnosticsReceiver() {}
+  ~TestDiagnosticsReceiver() final {}
+  TestDiagnosticsReceiver(PolicyDiagnosticsWaiter* waiter) { waiter_ = waiter; }
+  PolicyDiagnosticsWaiter* waiter_;
+  void ReceiveDiagnostics(std::unique_ptr<PolicyList> policies) override {
+    waiter_->policies = std::move(policies);
+    ::SetEvent(waiter_->event.Get());
+  }
+  void OnError(ResultCode error) override {
+    // Tests should not result in this function being called.
+    FAIL() << "OnError should not be called";
+  }
+};
+}  // namespace
+
 // Returns the current process state.
 SBOX_TESTS_COMMAND int IntegrationTestsTest_state(int argc, wchar_t **argv) {
   if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
@@ -67,6 +112,32 @@
   return argc;
 }
 
+// Sets the first named event, then waits on the second. This ensures
+// this process is alive and remains alive while its parent tests diagnostics.
+SBOX_TESTS_COMMAND int IntegrationTestsTest_event(int argc, wchar_t** argv) {
+  if (argc < 2)
+    return SBOX_TEST_INVALID_PARAMETER;
+
+  HANDLE hEventA =
+      ::OpenEventW(SYNCHRONIZE | EVENT_MODIFY_STATE, false, argv[0]);
+  if (!hEventA)
+    return SBOX_TEST_NOT_FOUND;
+  base::win::ScopedHandle handle_started(hEventA);
+
+  HANDLE hEventB = ::OpenEventW(SYNCHRONIZE, false, argv[1]);
+  if (!hEventB)
+    return SBOX_TEST_NOT_FOUND;
+  base::win::ScopedHandle handle_done(hEventB);
+
+  if (!::SetEvent(handle_started.Get()))
+    return SBOX_TEST_FIRST_ERROR;
+
+  if (WAIT_OBJECT_0 != ::WaitForSingleObject(handle_done.Get(), 1000))
+    return SBOX_TEST_SECOND_ERROR;
+
+  return SBOX_TEST_SUCCEEDED;
+}
+
 // Creates a job and tries to run a process inside it. The function can be
 // called with up to two parameters. The first one if set to "none" means that
 // the child process should be run with the JOB_NONE JobLevel else it is run
@@ -305,4 +376,71 @@
             runner.RunTest(L"IntegrationTestsTest_job none"));
 }
 
+// GetPolicyInfo validation
+TEST(IntegrationTestsTest, GetPolicyDiagnosticsReflectsActiveChildren) {
+  TestRunner runner;
+  // Unique event names so tests can run in parallel.
+  auto name_a = NonCollidingName();
+  auto name_done = NonCollidingName();
+
+  runner.SetTimeout(2000);
+  runner.SetAsynchronous(true);
+  runner.AddRule(TargetPolicy::SUBSYS_SYNC, TargetPolicy::EVENTS_ALLOW_ANY,
+                 name_a.c_str());
+  runner.AddRule(TargetPolicy::SUBSYS_SYNC, TargetPolicy::EVENTS_ALLOW_ANY,
+                 name_done.c_str());
+
+  // This helper can be reused if it has finished waiting.
+  auto waiter = std::make_unique<PolicyDiagnosticsWaiter>();
+  {
+    // But the receiver cannot be reused as it is consumed by GetPolicyInfo().
+    auto receiver = std::make_unique<TestDiagnosticsReceiver>(waiter.get());
+    auto result = runner.broker()->GetPolicyDiagnostics(std::move(receiver));
+    ASSERT_EQ(SBOX_ALL_OK, result);
+
+    // Initially no children so no policies.
+    auto policies = waiter->WaitForPolicies();
+    ASSERT_EQ(policies->size(), 0U);
+  }
+
+  HANDLE event_a = CreateEventW(nullptr, true, false, name_a.c_str());
+  base::win::ScopedHandle handle_started(event_a);
+  HANDLE event_done = CreateEventW(nullptr, true, false, name_done.c_str());
+  base::win::ScopedHandle handle_done(event_done);
+
+  auto cmd_line = base::string16(L"IntegrationTestsTest_event ");
+  cmd_line += name_a;
+  cmd_line += L" ";
+  cmd_line += name_done;
+
+  ASSERT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd_line.c_str()));
+  ASSERT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(handle_started.Get(), 1000));
+
+  {
+    // After starting a process, there should be one policy.
+    auto receiver = std::make_unique<TestDiagnosticsReceiver>(waiter.get());
+    ASSERT_EQ(SBOX_ALL_OK,
+              runner.broker()->GetPolicyDiagnostics(std::move(receiver)));
+    auto policies = waiter->WaitForPolicies();
+    ASSERT_EQ(policies->size(), 1U);
+  }
+
+  SetEvent(handle_done.Get());
+  ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets());
+
+  // TODO(ajgo) WaitForAllTargets is satisfied when the final process
+  // in a job exits but before the final job notification is received
+  // by the tracking thread. We have to give that notification a chance
+  // before we test to see if the job itself is removed.
+  SleepEx(100, true);
+  {
+    // Finally there should be no processes and no policies.
+    auto receiver = std::make_unique<TestDiagnosticsReceiver>(waiter.get());
+    ASSERT_EQ(SBOX_ALL_OK,
+              runner.broker()->GetPolicyDiagnostics(std::move(receiver)));
+    auto policies = waiter->WaitForPolicies();
+    ASSERT_EQ(policies->size(), 0U);
+  }
+}
+
 }  // namespace sandbox
diff --git a/services/data_decoder/data_decoder_service.cc b/services/data_decoder/data_decoder_service.cc
index bfcbd17..8647bb2 100644
--- a/services/data_decoder/data_decoder_service.cc
+++ b/services/data_decoder/data_decoder_service.cc
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/data_decoder/bundled_exchanges_parser_factory.h"
 #include "services/data_decoder/image_decoder_impl.h"
@@ -76,10 +77,11 @@
 }
 #endif  // OS_CHROMEOS
 
-void DataDecoderService::BindImageDecoder(mojom::ImageDecoderRequest request) {
-  mojo::MakeStrongBinding(
+void DataDecoderService::BindImageDecoder(
+    mojo::PendingReceiver<mojom::ImageDecoder> receiver) {
+  mojo::MakeSelfOwnedReceiver(
       std::make_unique<ImageDecoderImpl>(keepalive_.CreateRef()),
-      std::move(request));
+      std::move(receiver));
 }
 
 void DataDecoderService::BindJsonParser(mojom::JsonParserRequest request) {
diff --git a/services/data_decoder/data_decoder_service.h b/services/data_decoder/data_decoder_service.h
index 04e5caf..ff35c7b3 100644
--- a/services/data_decoder/data_decoder_service.h
+++ b/services/data_decoder/data_decoder_service.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "services/data_decoder/public/mojom/bundled_exchanges_parser.mojom.h"
 #include "services/data_decoder/public/mojom/image_decoder.mojom.h"
 #include "services/data_decoder/public/mojom/json_parser.mojom.h"
@@ -42,7 +43,7 @@
  private:
   void BindBundledExchangesParserFactory(
       mojom::BundledExchangesParserFactoryRequest request);
-  void BindImageDecoder(mojom::ImageDecoderRequest request);
+  void BindImageDecoder(mojo::PendingReceiver<mojom::ImageDecoder> receiver);
   void BindJsonParser(mojom::JsonParserRequest request);
   void BindXmlParser(mojom::XmlParserRequest request);
 
diff --git a/services/data_decoder/public/cpp/decode_image.cc b/services/data_decoder/public/cpp/decode_image.cc
index 0ae9eaf..0f67295 100644
--- a/services/data_decoder/public/cpp/decode_image.cc
+++ b/services/data_decoder/public/cpp/decode_image.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/data_decoder/public/mojom/constants.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -16,16 +17,16 @@
 
 namespace {
 
-// Helper callback which owns an ImageDecoderPtr until invoked. This keeps the
-// ImageDecoder pipe open just long enough to dispatch a reply, at which point
-// the reply is forwarded to the wrapped |callback|.
-void OnDecodeImage(mojom::ImageDecoderPtr decoder,
+// Helper callback which owns a mojo::Remote<ImageDecoder> until invoked. This
+// keeps the ImageDecoder pipe open just long enough to dispatch a reply, at
+// which point the reply is forwarded to the wrapped |callback|.
+void OnDecodeImage(mojo::Remote<mojom::ImageDecoder> decoder,
                    mojom::ImageDecoder::DecodeImageCallback callback,
                    const SkBitmap& bitmap) {
   std::move(callback).Run(bitmap);
 }
 
-void OnDecodeImages(mojom::ImageDecoderPtr decoder,
+void OnDecodeImages(mojo::Remote<mojom::ImageDecoder> decoder,
                     mojom::ImageDecoder::DecodeAnimationCallback callback,
                     std::vector<mojom::AnimationFramePtr> bitmaps) {
   std::move(callback).Run(std::move(bitmaps));
@@ -40,12 +41,12 @@
                  uint64_t max_size_in_bytes,
                  const gfx::Size& desired_image_frame_size,
                  mojom::ImageDecoder::DecodeImageCallback callback) {
-  mojom::ImageDecoderPtr decoder;
-  connector->BindInterface(mojom::kServiceName, &decoder);
+  mojo::Remote<mojom::ImageDecoder> decoder;
+  connector->Connect(mojom::kServiceName, decoder.BindNewPipeAndPassReceiver());
 
   // |call_once| runs |callback| on its first invocation.
   auto call_once = base::AdaptCallbackForRepeating(std::move(callback));
-  decoder.set_connection_error_handler(base::Bind(call_once, SkBitmap()));
+  decoder.set_disconnect_handler(base::Bind(call_once, SkBitmap()));
 
   mojom::ImageDecoder* raw_decoder = decoder.get();
   raw_decoder->DecodeImage(
@@ -59,12 +60,12 @@
                      bool shrink_to_fit,
                      uint64_t max_size_in_bytes,
                      mojom::ImageDecoder::DecodeAnimationCallback callback) {
-  mojom::ImageDecoderPtr decoder;
-  connector->BindInterface(mojom::kServiceName, &decoder);
+  mojo::Remote<mojom::ImageDecoder> decoder;
+  connector->Connect(mojom::kServiceName, decoder.BindNewPipeAndPassReceiver());
 
   // |call_once| runs |callback| on its first invocation.
   auto call_once = base::AdaptCallbackForRepeating(std::move(callback));
-  decoder.set_connection_error_handler(base::Bind(
+  decoder.set_disconnect_handler(base::Bind(
       call_once, base::Passed(std::vector<mojom::AnimationFramePtr>())));
 
   mojom::ImageDecoder* raw_decoder = decoder.get();
diff --git a/services/data_decoder/public/cpp/test_data_decoder_service.cc b/services/data_decoder/public/cpp/test_data_decoder_service.cc
index 02cc6d7..a71ff92 100644
--- a/services/data_decoder/public/cpp/test_data_decoder_service.cc
+++ b/services/data_decoder/public/cpp/test_data_decoder_service.cc
@@ -4,6 +4,7 @@
 
 #include "services/data_decoder/public/cpp/test_data_decoder_service.h"
 
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "services/data_decoder/data_decoder_service.h"
 #include "services/data_decoder/public/mojom/constants.mojom.h"
 
@@ -43,10 +44,11 @@
     return;
   }
   if (interface_name == mojom::ImageDecoder::Name_ && crash_image_) {
-    DCHECK(!image_decoder_binding_);
-    image_decoder_binding_ =
-        std::make_unique<mojo::Binding<mojom::ImageDecoder>>(
-            this, mojom::ImageDecoderRequest(std::move(interface_pipe)));
+    DCHECK(!image_decoder_receiver_);
+    image_decoder_receiver_ =
+        std::make_unique<mojo::Receiver<mojom::ImageDecoder>>(
+            this, mojo::PendingReceiver<mojom::ImageDecoder>(
+                      std::move(interface_pipe)));
     return;
   }
   real_service_.OnBindInterface(source_info, interface_name,
@@ -61,7 +63,7 @@
     int64_t max_size_in_bytes,
     const gfx::Size& desired_image_frame_size,
     DecodeImageCallback callback) {
-  image_decoder_binding_.reset();
+  image_decoder_receiver_.reset();
 }
 
 void CrashyDataDecoderService::DecodeAnimation(
@@ -69,7 +71,7 @@
     bool shrink_to_fit,
     int64_t max_size_in_bytes,
     DecodeAnimationCallback callback) {
-  image_decoder_binding_.reset();
+  image_decoder_receiver_.reset();
 }
 
 void CrashyDataDecoderService::Parse(const std::string& json,
diff --git a/services/data_decoder/public/cpp/test_data_decoder_service.h b/services/data_decoder/public/cpp/test_data_decoder_service.h
index 36b92f2..ae252ae 100644
--- a/services/data_decoder/public/cpp/test_data_decoder_service.h
+++ b/services/data_decoder/public/cpp/test_data_decoder_service.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "services/data_decoder/data_decoder_service.h"
 #include "services/data_decoder/public/mojom/image_decoder.mojom.h"
 #include "services/data_decoder/public/mojom/json_parser.mojom.h"
@@ -78,7 +79,7 @@
  private:
   service_manager::ServiceBinding binding_;
 
-  std::unique_ptr<mojo::Binding<mojom::ImageDecoder>> image_decoder_binding_;
+  std::unique_ptr<mojo::Receiver<mojom::ImageDecoder>> image_decoder_receiver_;
   std::unique_ptr<mojo::Binding<mojom::JsonParser>> json_parser_binding_;
 
   // An instance of the actual DataDecoderService we forward requests to for
diff --git a/storage/browser/blob/blob_handle.cc b/storage/browser/blob/blob_handle.cc
index 1d6db68..31129332 100644
--- a/storage/browser/blob/blob_handle.cc
+++ b/storage/browser/blob/blob_handle.cc
@@ -6,13 +6,14 @@
 
 namespace storage {
 
-BlobHandle::BlobHandle(blink::mojom::BlobPtr blob) : blob_(std::move(blob)) {
+BlobHandle::BlobHandle(mojo::PendingRemote<blink::mojom::Blob> blob)
+    : blob_(std::move(blob)) {
   DCHECK(blob_);
 }
 
-blink::mojom::BlobPtr BlobHandle::Clone() const {
-  blink::mojom::BlobPtr clone;
-  blob_->Clone(MakeRequest(&clone));
+mojo::PendingRemote<blink::mojom::Blob> BlobHandle::Clone() const {
+  mojo::PendingRemote<blink::mojom::Blob> clone;
+  blob_->Clone(clone.InitWithNewPipeAndPassReceiver());
   return clone;
 }
 
diff --git a/storage/browser/blob/blob_handle.h b/storage/browser/blob/blob_handle.h
index 9b3e7de..4050dff5 100644
--- a/storage/browser/blob/blob_handle.h
+++ b/storage/browser/blob/blob_handle.h
@@ -7,29 +7,30 @@
 
 #include "base/component_export.h"
 #include "base/memory/ref_counted.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom.h"
 
 namespace storage {
 
-// Refcounted wrapper around a mojom::BlobPtr.
+// Refcounted wrapper around a mojom::Blob.
 class COMPONENT_EXPORT(STORAGE_BROWSER) BlobHandle
     : public base::RefCounted<BlobHandle> {
  public:
-  explicit BlobHandle(blink::mojom::BlobPtr blob);
+  explicit BlobHandle(mojo::PendingRemote<blink::mojom::Blob> blob);
 
   bool is_bound() const { return blob_.is_bound(); }
   blink::mojom::Blob* get() const { return blob_.get(); }
   blink::mojom::Blob* operator->() const { return get(); }
   blink::mojom::Blob& operator*() const { return *get(); }
 
-  blink::mojom::BlobPtr Clone() const;
-  blink::mojom::BlobPtr&& TakeBlobPtr() { return std::move(blob_); }
+  mojo::PendingRemote<blink::mojom::Blob> Clone() const;
 
  private:
   friend class base::RefCounted<BlobHandle>;
   ~BlobHandle();
 
-  blink::mojom::BlobPtr blob_;
+  mojo::Remote<blink::mojom::Blob> blob_;
 };
 
 }  // namespace storage
diff --git a/storage/browser/blob/blob_impl_unittest.cc b/storage/browser/blob/blob_impl_unittest.cc
index c6d75d9..460a0cb 100644
--- a/storage/browser/blob/blob_impl_unittest.cc
+++ b/storage/browser/blob/blob_impl_unittest.cc
@@ -13,7 +13,9 @@
 #include "base/run_loop.h"
 #include "base/task/post_task.h"
 #include "base/test/task_environment.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/system/data_pipe_drainer.h"
 #include "net/base/net_errors.h"
 #include "storage/browser/blob/blob_data_builder.h"
@@ -111,30 +113,32 @@
   const std::string kId = "id";
   auto handle = CreateBlobFromString(kId, "hello world");
 
-  blink::mojom::BlobPtr ptr;
-  auto blob = BlobImpl::Create(std::move(handle), MakeRequest(&ptr));
+  mojo::Remote<blink::mojom::Blob> remote;
+  auto blob =
+      BlobImpl::Create(std::move(handle), remote.BindNewPipeAndPassReceiver());
   EXPECT_EQ(kId, UUIDFromBlob(blob.get()));
-  EXPECT_EQ(kId, UUIDFromBlob(ptr.get()));
+  EXPECT_EQ(kId, UUIDFromBlob(remote.get()));
 }
 
 TEST_F(BlobImplTest, CloneAndLifetime) {
   const std::string kId = "id";
   auto handle = CreateBlobFromString(kId, "hello world");
 
-  blink::mojom::BlobPtr ptr;
-  auto blob = BlobImpl::Create(std::move(handle), MakeRequest(&ptr));
-  EXPECT_EQ(kId, UUIDFromBlob(ptr.get()));
+  mojo::Remote<blink::mojom::Blob> remote;
+  auto blob =
+      BlobImpl::Create(std::move(handle), remote.BindNewPipeAndPassReceiver());
+  EXPECT_EQ(kId, UUIDFromBlob(remote.get()));
 
   // Blob should exist in registry as long as connection is alive.
   EXPECT_TRUE(context_->registry().HasEntry(kId));
   EXPECT_TRUE(blob);
 
-  blink::mojom::BlobPtr clone;
-  blob->Clone(MakeRequest(&clone));
+  mojo::Remote<blink::mojom::Blob> clone;
+  blob->Clone(clone.BindNewPipeAndPassReceiver());
   EXPECT_EQ(kId, UUIDFromBlob(clone.get()));
   clone.FlushForTesting();
 
-  ptr.reset();
+  remote.reset();
   blob->FlushForTesting();
   EXPECT_TRUE(context_->registry().HasEntry(kId));
   EXPECT_TRUE(blob);
@@ -150,15 +154,15 @@
   const std::string kContents = "hello world";
   auto handle = CreateBlobFromString(kId, kContents);
 
-  blink::mojom::BlobPtr ptr;
-  BlobImpl::Create(std::move(handle), MakeRequest(&ptr));
+  mojo::Remote<blink::mojom::Blob> remote;
+  BlobImpl::Create(std::move(handle), remote.BindNewPipeAndPassReceiver());
 
   MockBlobReaderClient client;
   mojo::Receiver<blink::mojom::BlobReaderClient> client_receiver(&client);
 
   mojo::DataPipe pipe;
-  ptr->ReadAll(std::move(pipe.producer_handle),
-               client_receiver.BindNewPipeAndPassRemote());
+  remote->ReadAll(std::move(pipe.producer_handle),
+                  client_receiver.BindNewPipeAndPassRemote());
   std::string received = ReadDataPipe(std::move(pipe.consumer_handle));
   EXPECT_EQ(kContents, received);
 
@@ -177,11 +181,11 @@
   const std::string kContents = "hello world";
   auto handle = CreateBlobFromString(kId, kContents);
 
-  blink::mojom::BlobPtr ptr;
-  BlobImpl::Create(std::move(handle), MakeRequest(&ptr));
+  mojo::Remote<blink::mojom::Blob> remote;
+  BlobImpl::Create(std::move(handle), remote.BindNewPipeAndPassReceiver());
 
   mojo::DataPipe pipe;
-  ptr->ReadAll(std::move(pipe.producer_handle), mojo::NullRemote());
+  remote->ReadAll(std::move(pipe.producer_handle), mojo::NullRemote());
   std::string received = ReadDataPipe(std::move(pipe.consumer_handle));
   EXPECT_EQ(kContents, received);
 }
@@ -191,15 +195,15 @@
   auto handle = context_->AddBrokenBlob(
       kId, "", "", BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS);
 
-  blink::mojom::BlobPtr ptr;
-  BlobImpl::Create(std::move(handle), MakeRequest(&ptr));
+  mojo::Remote<blink::mojom::Blob> remote;
+  BlobImpl::Create(std::move(handle), remote.BindNewPipeAndPassReceiver());
 
   MockBlobReaderClient client;
   mojo::Receiver<blink::mojom::BlobReaderClient> client_receiver(&client);
 
   mojo::DataPipe pipe;
-  ptr->ReadAll(std::move(pipe.producer_handle),
-               client_receiver.BindNewPipeAndPassRemote());
+  remote->ReadAll(std::move(pipe.producer_handle),
+                  client_receiver.BindNewPipeAndPassRemote());
 
   std::string received = ReadDataPipe(std::move(pipe.consumer_handle));
   EXPECT_EQ("", received);
@@ -216,15 +220,15 @@
   const std::string kContents = "hello world";
   auto handle = CreateBlobFromString(kId, kContents);
 
-  blink::mojom::BlobPtr ptr;
-  BlobImpl::Create(std::move(handle), MakeRequest(&ptr));
+  mojo::Remote<blink::mojom::Blob> remote;
+  BlobImpl::Create(std::move(handle), remote.BindNewPipeAndPassReceiver());
 
   MockBlobReaderClient client;
   mojo::Receiver<blink::mojom::BlobReaderClient> client_receiver(&client);
 
   mojo::DataPipe pipe;
-  ptr->ReadRange(2, 5, std::move(pipe.producer_handle),
-                 client_receiver.BindNewPipeAndPassRemote());
+  remote->ReadRange(2, 5, std::move(pipe.producer_handle),
+                    client_receiver.BindNewPipeAndPassRemote());
 
   std::string received = ReadDataPipe(std::move(pipe.consumer_handle));
   EXPECT_EQ(kContents.substr(2, 5), received);
@@ -244,11 +248,11 @@
   const std::string kContents = "hello world";
   auto handle = CreateBlobFromString(kId, kContents);
 
-  blink::mojom::BlobPtr ptr;
-  BlobImpl::Create(std::move(handle), MakeRequest(&ptr));
+  mojo::Remote<blink::mojom::Blob> remote;
+  BlobImpl::Create(std::move(handle), remote.BindNewPipeAndPassReceiver());
 
   mojo::DataPipe pipe;
-  ptr->ReadRange(2, 5, std::move(pipe.producer_handle), mojo::NullRemote());
+  remote->ReadRange(2, 5, std::move(pipe.producer_handle), mojo::NullRemote());
 
   std::string received = ReadDataPipe(std::move(pipe.consumer_handle));
   EXPECT_EQ(kContents.substr(2, 5), received);
@@ -259,15 +263,15 @@
   const std::string kContents = "hello world";
   auto handle = CreateBlobFromString(kId, kContents);
 
-  blink::mojom::BlobPtr ptr;
-  BlobImpl::Create(std::move(handle), MakeRequest(&ptr));
+  mojo::Remote<blink::mojom::Blob> remote;
+  BlobImpl::Create(std::move(handle), remote.BindNewPipeAndPassReceiver());
 
   MockBlobReaderClient client;
   mojo::Receiver<blink::mojom::BlobReaderClient> client_receiver(&client);
 
   mojo::DataPipe pipe;
-  ptr->ReadRange(2, 15, std::move(pipe.producer_handle),
-                 client_receiver.BindNewPipeAndPassRemote());
+  remote->ReadRange(2, 15, std::move(pipe.producer_handle),
+                    client_receiver.BindNewPipeAndPassRemote());
 
   std::string received = ReadDataPipe(std::move(pipe.consumer_handle));
   EXPECT_EQ(kContents.substr(2, 15), received);
@@ -287,16 +291,16 @@
   const std::string kContents = "hello world";
   auto handle = CreateBlobFromString(kId, kContents);
 
-  blink::mojom::BlobPtr ptr;
-  BlobImpl::Create(std::move(handle), MakeRequest(&ptr));
+  mojo::Remote<blink::mojom::Blob> remote;
+  BlobImpl::Create(std::move(handle), remote.BindNewPipeAndPassReceiver());
 
   MockBlobReaderClient client;
   mojo::Receiver<blink::mojom::BlobReaderClient> client_receiver(&client);
 
   mojo::DataPipe pipe;
-  ptr->ReadRange(2, std::numeric_limits<uint64_t>::max(),
-                 std::move(pipe.producer_handle),
-                 client_receiver.BindNewPipeAndPassRemote());
+  remote->ReadRange(2, std::numeric_limits<uint64_t>::max(),
+                    std::move(pipe.producer_handle),
+                    client_receiver.BindNewPipeAndPassRemote());
 
   std::string received = ReadDataPipe(std::move(pipe.consumer_handle));
   EXPECT_EQ(kContents.substr(2, kContents.size()), received);
@@ -316,15 +320,15 @@
   auto handle = context_->AddBrokenBlob(
       kId, "", "", BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS);
 
-  blink::mojom::BlobPtr ptr;
-  BlobImpl::Create(std::move(handle), MakeRequest(&ptr));
+  mojo::Remote<blink::mojom::Blob> remote;
+  BlobImpl::Create(std::move(handle), remote.BindNewPipeAndPassReceiver());
 
   MockBlobReaderClient client;
   mojo::Receiver<blink::mojom::BlobReaderClient> client_receiver(&client);
 
   mojo::DataPipe pipe;
-  ptr->ReadRange(2, 5, std::move(pipe.producer_handle),
-                 client_receiver.BindNewPipeAndPassRemote());
+  remote->ReadRange(2, 5, std::move(pipe.producer_handle),
+                    client_receiver.BindNewPipeAndPassRemote());
 
   std::string received = ReadDataPipe(std::move(pipe.consumer_handle));
   EXPECT_EQ("", received);
@@ -341,16 +345,16 @@
   const std::string kContents = "hello world";
   auto handle = CreateBlobFromString(kId, kContents);
 
-  blink::mojom::BlobPtr ptr;
-  BlobImpl::Create(std::move(handle), MakeRequest(&ptr));
+  mojo::Remote<blink::mojom::Blob> remote;
+  BlobImpl::Create(std::move(handle), remote.BindNewPipeAndPassReceiver());
 
   MockBlobReaderClient client;
   mojo::Receiver<blink::mojom::BlobReaderClient> client_receiver(&client);
 
   base::RunLoop loop;
   mojo::DataPipe pipe;
-  ptr->ReadRange(15, 4, std::move(pipe.producer_handle),
-                 client_receiver.BindNewPipeAndPassRemote());
+  remote->ReadRange(15, 4, std::move(pipe.producer_handle),
+                    client_receiver.BindNewPipeAndPassRemote());
 
   std::string received = ReadDataPipe(std::move(pipe.consumer_handle));
   EXPECT_EQ("", received);
diff --git a/storage/browser/blob/blob_registry_impl.cc b/storage/browser/blob/blob_registry_impl.cc
index 8e37c517..1cc34f91 100644
--- a/storage/browser/blob/blob_registry_impl.cc
+++ b/storage/browser/blob/blob_registry_impl.cc
@@ -58,8 +58,9 @@
 
  private:
   // Holds onto a blink::mojom::DataElement struct and optionally a bound
-  // mojo::Remote<blink::mojom::BytesProvider> or blink::mojom::BlobPtr, if the
-  // element encapsulates a large byte array or a blob.
+  // mojo::Remote<blink::mojom::BytesProvider> or
+  // mojo::Remote<blink::mojom::Blob>, if the element encapsulates a large byte
+  // array or a blob.
   struct ElementEntry {
     explicit ElementEntry(blink::mojom::DataElementPtr e)
         : element(std::move(e)) {
@@ -76,7 +77,7 @@
 
     blink::mojom::DataElementPtr element;
     mojo::Remote<blink::mojom::BytesProvider> bytes_provider;
-    blink::mojom::BlobPtr blob;
+    mojo::Remote<blink::mojom::Blob> blob;
   };
 
   BlobStorageContext* context() const { return blob_registry_->context_.get(); }
@@ -220,7 +221,7 @@
       // If connection to blob is broken, something bad happened, so mark this
       // new blob as broken, which will delete |this| and keep it from doing
       // unneeded extra work.
-      entry.blob.set_connection_error_handler(base::BindOnce(
+      entry.blob.set_disconnect_handler(base::BindOnce(
           &BlobUnderConstruction::MarkAsBroken, weak_ptr_factory_.GetWeakPtr(),
           BlobStatus::ERR_REFERENCED_BLOB_BROKEN, ""));
 
@@ -237,7 +238,8 @@
 
   // TODO(mek): Do we need some kind of timeout for fetching the UUIDs?
   // Without it a blob could forever remaing pending if a renderer sends us
-  // a BlobPtr connected to a (malicious) non-responding implementation.
+  // a mojo::Remote<Blob> connected to a (malicious) non-responding
+  // implementation.
 
   // Do some basic validation of bytes to transport, and determine memory
   // transport strategy to use later.
diff --git a/storage/browser/blob/blob_registry_impl_unittest.cc b/storage/browser/blob/blob_registry_impl_unittest.cc
index 62a8b56..3182e7af 100644
--- a/storage/browser/blob/blob_registry_impl_unittest.cc
+++ b/storage/browser/blob/blob_registry_impl_unittest.cc
@@ -23,7 +23,6 @@
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/system/data_pipe_utils.h"
 #include "storage/browser/blob/blob_data_builder.h"
 #include "storage/browser/blob/blob_data_handle.h"
@@ -206,26 +205,26 @@
       CreateBlobFromString(kId, "hello world");
 
   {
-    blink::mojom::BlobPtr blob;
-    registry_->GetBlobFromUUID(MakeRequest(&blob), kId);
+    mojo::Remote<blink::mojom::Blob> blob;
+    registry_->GetBlobFromUUID(blob.BindNewPipeAndPassReceiver(), kId);
     EXPECT_EQ(kId, UUIDFromBlob(blob.get()));
-    EXPECT_FALSE(blob.encountered_error());
+    EXPECT_TRUE(blob.is_connected());
   }
 
   {
-    blink::mojom::BlobPtr blob;
-    registry_->GetBlobFromUUID(MakeRequest(&blob), "invalid id");
+    mojo::Remote<blink::mojom::Blob> blob;
+    registry_->GetBlobFromUUID(blob.BindNewPipeAndPassReceiver(), "invalid id");
     blob.FlushForTesting();
-    EXPECT_TRUE(blob.encountered_error());
+    EXPECT_FALSE(blob.is_connected());
   }
 }
 
 TEST_F(BlobRegistryImplTest, GetBlobFromEmptyUUID) {
-  blink::mojom::BlobPtr blob;
-  registry_->GetBlobFromUUID(MakeRequest(&blob), "");
+  mojo::Remote<blink::mojom::Blob> blob;
+  registry_->GetBlobFromUUID(blob.BindNewPipeAndPassReceiver(), "");
   blob.FlushForTesting();
   EXPECT_EQ(1u, bad_messages_.size());
-  EXPECT_TRUE(blob.encountered_error());
+  EXPECT_FALSE(blob.is_connected());
 }
 
 TEST_F(BlobRegistryImplTest, Register_EmptyUUID) {
@@ -294,11 +293,11 @@
   const std::string kId = "id";
 
   std::vector<blink::mojom::DataElementPtr> elements;
-  blink::mojom::BlobPtrInfo referenced_blob_info;
-  MakeRequest(&referenced_blob_info);
+  mojo::PendingRemote<blink::mojom::Blob> referenced_blob_remote;
+  ignore_result(referenced_blob_remote.InitWithNewPipeAndPassReceiver());
   elements.push_back(
       blink::mojom::DataElement::NewBlob(blink::mojom::DataElementBlob::New(
-          std::move(referenced_blob_info), 0, 16)));
+          std::move(referenced_blob_remote), 0, 16)));
 
   mojo::PendingRemote<blink::mojom::Blob> blob;
   EXPECT_TRUE(registry_->Register(blob.InitWithNewPipeAndPassReceiver(), kId,
@@ -415,12 +414,13 @@
   const std::string kId = "id";
 
   std::vector<blink::mojom::DataElementPtr> elements;
-  blink::mojom::BlobPtrInfo referenced_blob_info;
-  mojo::MakeStrongBinding(std::make_unique<FakeBlob>("mock blob"),
-                          MakeRequest(&referenced_blob_info));
+  mojo::PendingRemote<blink::mojom::Blob> referenced_blob_remote;
+  mojo::MakeSelfOwnedReceiver(
+      std::make_unique<FakeBlob>("mock blob"),
+      referenced_blob_remote.InitWithNewPipeAndPassReceiver());
   elements.push_back(
       blink::mojom::DataElement::NewBlob(blink::mojom::DataElementBlob::New(
-          std::move(referenced_blob_info), 0, 16)));
+          std::move(referenced_blob_remote), 0, 16)));
 
   mojo::PendingRemote<blink::mojom::Blob> blob;
   EXPECT_TRUE(registry_->Register(blob.InitWithNewPipeAndPassReceiver(), kId,
@@ -445,9 +445,9 @@
   const std::string kId1 = "id1";
   std::unique_ptr<BlobDataHandle> handle =
       CreateBlobFromString(kId1, "hello world");
-  blink::mojom::BlobPtrInfo blob1_info;
-  mojo::MakeStrongBinding(std::make_unique<FakeBlob>(kId1),
-                          MakeRequest(&blob1_info));
+  mojo::PendingRemote<blink::mojom::Blob> blob1_remote;
+  mojo::MakeSelfOwnedReceiver(std::make_unique<FakeBlob>(kId1),
+                              blob1_remote.InitWithNewPipeAndPassReceiver());
 
   const std::string kId2 = "id2";
   mojo::PendingRemote<blink::mojom::Blob> blob2_remote;
@@ -456,7 +456,7 @@
 
   std::vector<blink::mojom::DataElementPtr> elements1;
   elements1.push_back(blink::mojom::DataElement::NewBlob(
-      blink::mojom::DataElementBlob::New(std::move(blob1_info), 0, 8)));
+      blink::mojom::DataElementBlob::New(std::move(blob1_remote), 0, 8)));
 
   std::vector<blink::mojom::DataElementPtr> elements2;
   elements2.push_back(blink::mojom::DataElement::NewBlob(
@@ -916,15 +916,16 @@
   // Create future blob.
   auto blob_handle = context_->AddFutureBlob(
       kDepId, "", "", BlobStorageContext::BuildAbortedCallback());
-  blink::mojom::BlobPtrInfo referenced_blob_info;
-  mojo::MakeStrongBinding(std::make_unique<FakeBlob>(kDepId),
-                          MakeRequest(&referenced_blob_info));
+  mojo::PendingRemote<blink::mojom::Blob> referenced_blob_remote;
+  mojo::MakeSelfOwnedReceiver(
+      std::make_unique<FakeBlob>(kDepId),
+      referenced_blob_remote.InitWithNewPipeAndPassReceiver());
 
   // Create mojo blob depending on future blob.
   std::vector<blink::mojom::DataElementPtr> elements;
   elements.push_back(
       blink::mojom::DataElement::NewBlob(blink::mojom::DataElementBlob::New(
-          std::move(referenced_blob_info), 0, kData.size())));
+          std::move(referenced_blob_remote), 0, kData.size())));
 
   mojo::PendingRemote<blink::mojom::Blob> blob;
   EXPECT_TRUE(registry_->Register(blob.InitWithNewPipeAndPassReceiver(), kId,
diff --git a/storage/browser/test/fake_blob.cc b/storage/browser/test/fake_blob.cc
index 4495b99..2c70ad1 100644
--- a/storage/browser/test/fake_blob.cc
+++ b/storage/browser/test/fake_blob.cc
@@ -10,9 +10,9 @@
 
 FakeBlob::FakeBlob(const std::string& uuid) : uuid_(uuid) {}
 
-blink::mojom::BlobPtr FakeBlob::Clone() {
-  blink::mojom::BlobPtr result;
-  Clone(MakeRequest(&result));
+mojo::PendingRemote<blink::mojom::Blob> FakeBlob::Clone() {
+  mojo::PendingRemote<blink::mojom::Blob> result;
+  Clone(result.InitWithNewPipeAndPassReceiver());
   return result;
 }
 
diff --git a/storage/browser/test/fake_blob.h b/storage/browser/test/fake_blob.h
index 2d71e178..620facf 100644
--- a/storage/browser/test/fake_blob.h
+++ b/storage/browser/test/fake_blob.h
@@ -5,6 +5,7 @@
 #ifndef STORAGE_BROWSER_TEST_FAKE_BLOB_H_
 #define STORAGE_BROWSER_TEST_FAKE_BLOB_H_
 
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom.h"
 
 namespace storage {
@@ -15,7 +16,7 @@
  public:
   explicit FakeBlob(const std::string& uuid);
 
-  blink::mojom::BlobPtr Clone();
+  mojo::PendingRemote<blink::mojom::Blob> Clone();
   void Clone(mojo::PendingReceiver<blink::mojom::Blob> receiver) override;
   void AsDataPipeGetter(
       mojo::PendingReceiver<network::mojom::DataPipeGetter>) override;
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 20f546f2..5366f9b 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -1325,6 +1325,62 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "chromium/third_party/android_sdk/public/avds/android-23/google_apis/x86",
+              "location": ".android",
+              "revision": "cfoclSzHrFOS_AcwBL09RQ5PvJByQHu3MX6EbC5aWZIC"
+            },
+            {
+              "cipd_package": "chromium/third_party/android_sdk/public/emulator",
+              "location": "third_party/android_sdk/public",
+              "revision": "f4WdgkPvDdVCE8zBWPzcSIj4N9WFhKp3CSKDWylXuLEC"
+            },
+            {
+              "cipd_package": "chromium/third_party/android_sdk/public/system-images/android-23/google_apis/x86",
+              "location": "third_party/android_sdk/public",
+              "revision": "npuCAATVbhmywZwGhI3tMoECTrBBzzyJLpjAPXqtmYYC"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "os": "Ubuntu-16.04"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-name=20190903T160000Z_android_23_google_apis_x86",
+          "--emulator-home=../../.android"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 2531957..350272a1 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -8518,6 +8518,51 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "LMY48I",
+              "device_os_type": "userdebug",
+              "device_type": "hammerhead",
+              "os": "Android"
+            }
+          ],
+          "expiration": 10800,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -11751,6 +11796,51 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "LMY49B",
+              "device_os_type": "userdebug",
+              "device_type": "flo",
+              "os": "Android"
+            }
+          ],
+          "expiration": 10800,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -14679,6 +14769,50 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_os_type": "userdebug",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -17856,6 +17990,51 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MRA58Z",
+              "device_os_type": "userdebug",
+              "device_type": "flo",
+              "os": "Android"
+            }
+          ],
+          "expiration": 10800,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -20230,6 +20409,41 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "monochrome_public_bundle_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "device_os": "NMF26U",
+              "device_os_type": "userdebug",
+              "device_type": "marlin",
+              "os": "Android"
+            }
+          ]
+        },
+        "test": "monochrome_public_bundle_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "monochrome_public_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -20552,6 +20766,50 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "monochrome_public_bundle_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "OPR3.170623.008",
+              "device_os_type": "userdebug",
+              "device_type": "marlin",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "monochrome_public_bundle_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "monochrome_public_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -25907,6 +26165,50 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_os_type": "userdebug",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -28409,6 +28711,50 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "monochrome_public_bundle_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "PQ1A.190105.004",
+              "device_os_type": "userdebug",
+              "device_type": "walleye",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "monochrome_public_bundle_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "monochrome_public_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -28591,6 +28937,51 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "monochrome_public_bundle_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "PQ3A.190801.002",
+              "device_os_flavor": "google",
+              "device_os_type": "userdebug",
+              "device_type": "walleye",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "monochrome_public_bundle_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "monochrome_public_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index d2d4f0f2..ec4ab2f72 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -1592,22 +1592,6 @@
               "cpu": "x86-64",
               "os": "Windows-10-15063"
             }
-          ]
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
           ],
           "shards": 10
         },
@@ -3255,22 +3239,6 @@
             }
           ]
         },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "cacheinvalidation_unittests"
       },
       {
@@ -23971,16 +23939,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
         },
@@ -25022,16 +24980,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 20
         },
@@ -26073,16 +26021,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
         },
@@ -27208,22 +27146,6 @@
               "cpu": "x86-64",
               "os": "Windows-10-15063"
             }
-          ]
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
           ],
           "shards": 10
         },
@@ -28853,22 +28775,6 @@
               "cpu": "x86-64",
               "os": "Windows-10-15063"
             }
-          ]
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
           ],
           "shards": 20
         },
@@ -30498,22 +30404,6 @@
               "cpu": "x86-64",
               "os": "Windows-10-15063"
             }
-          ]
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
           ],
           "shards": 10
         },
@@ -32059,16 +31949,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
         },
@@ -33110,16 +32990,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
         },
@@ -34161,16 +34031,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
         },
@@ -35212,16 +35072,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
         },
@@ -36263,16 +36113,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
         },
@@ -38771,21 +38611,6 @@
         "test": "boringssl_ssl_tests"
       },
       {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
         "args": [
           "--disable-blink-features=HTMLImports,ShadowDOMV0,CustomElementsV0",
           "--test-launcher-filter-file=../../testing/buildbot/filters/webui_html_imports_polyfill_browser_tests.filter"
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 9e1cf1d..9be031ce 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -1211,16 +1211,6 @@
         "swarming": {
           "can_use_on_swarming_builders": false
         },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": false
-        },
         "test": "browser_tests"
       },
       {
@@ -2401,22 +2391,6 @@
               "cpu": "x86-64",
               "os": "Windows-10-17134"
             }
-          ]
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-17134"
-            }
           ],
           "shards": 10
         },
@@ -4933,6 +4907,51 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_modern_public_bundle_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_os_type": "userdebug",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "chrome_modern_public_bundle_smoke_test"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "isolate_coverage_data": true,
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_modern_public_smoke_test"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index af3c7d8..ce82193 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -17133,21 +17133,6 @@
             {
               "os": "Windows-10-15063"
             }
-          ]
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Windows-10-15063"
-            }
           ],
           "shards": 10
         },
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index c508882..254e09f 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -156,16 +156,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
         },
@@ -1486,22 +1476,6 @@
         "test": "boringssl_ssl_tests"
       },
       {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
         "args": [
           "--disable-features=WebRTC-H264WithOpenH264FFmpeg"
         ],
@@ -3385,22 +3359,6 @@
             }
           ]
         },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "cacheinvalidation_unittests"
       },
       {
@@ -5222,16 +5180,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 15
         },
@@ -6481,16 +6429,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "browser_switcher_bho_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 20
         },
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index de737a7..ff7e949 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -467,10 +467,6 @@
     "label": "//third_party/brotli:brotli_fuzzer",
     "type": "fuzzer",
   },
-  "browser_switcher_bho_unittests": {
-    "label": "//chrome/browser/browser_switcher/bho:browser_switcher_bho_unittests",
-    "type": "console_test_launcher",
-  },
   "browser_tests": {
     "label": "//chrome/test:browser_tests",
     "type": "windowed_test_launcher",
@@ -624,6 +620,10 @@
     "label": "//chrome/android:chrome_modern_public_smoke_test",
     "type": "console_test_launcher",
   },
+  "chrome_modern_public_bundle_smoke_test": {
+    "label": "//chrome/android:chrome_modern_public_bundle_smoke_test",
+    "type": "console_test_launcher",
+  },
   "chrome_official_builder": {
     "label": "//:chrome_official_builder",
     "type": "additional_compile_target",
@@ -1744,6 +1744,10 @@
     "label": "//chrome/android:monochrome_public_smoke_test",
     "type": "console_test_launcher",
   },
+  "monochrome_public_bundle_smoke_test": {
+    "label": "//chrome/android:monochrome_public_bundle_smoke_test",
+    "type": "console_test_launcher",
+  },
   "mojo_core_channel_fuzzer": {
     "label": "//mojo/core:mojo_core_channel_fuzzer",
     "type": "fuzzer",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index d08544f..b614134 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -83,10 +83,12 @@
 
     'android_modern_smoke_tests': {
       'chrome_modern_public_smoke_test': {},
+      'chrome_modern_public_bundle_smoke_test': {},
     },
 
     'android_monochrome_smoke_tests': {
       'monochrome_public_smoke_test': {},
+      'monochrome_public_bundle_smoke_test': {},
     },
 
     'android_oreo_standard_gtests': {
@@ -5001,7 +5003,6 @@
     },
 
     'win_specific_chromium_gtests': {
-      'browser_switcher_bho_unittests': {},
       'chrome_cleaner_unittests': {},
       'chrome_elf_unittests': {},
       'courgette_unittests': {},
diff --git a/testing/test_env.py b/testing/test_env.py
index 13808a2f..eac46bf 100755
--- a/testing/test_env.py
+++ b/testing/test_env.py
@@ -189,8 +189,8 @@
   assert stdoutfile
   with io.open(stdoutfile, 'wb') as writer, \
       io.open(stdoutfile, 'rb', 1) as reader:
-    process = subprocess.Popen(argv, env=env, cwd=cwd, stdout=writer,
-        stderr=subprocess.STDOUT)
+    process = _popen(argv, env=env, cwd=cwd, stdout=writer,
+                     stderr=subprocess.STDOUT)
     forward_signals([process])
     while process.poll() is None:
       sys.stdout.write(reader.read())
@@ -214,7 +214,7 @@
   """
   if log:
     print('Running %r in %r (env: %r)' % (argv, cwd, env))
-  process = subprocess.Popen(argv, env=env, cwd=cwd, stderr=subprocess.STDOUT)
+  process = _popen(argv, env=env, cwd=cwd, stderr=subprocess.STDOUT)
   forward_signals([process])
   return wait_with_signals(process)
 
@@ -229,7 +229,7 @@
     integer returncode of the subprocess.
   """
   print('Running %r in %r (env: %r)' % (argv, cwd, env))
-  process = subprocess.Popen(
+  process = _popen(
       argv, env=env, cwd=cwd, stderr=file_handle, stdout=file_handle)
   forward_signals([process])
   exit_code = wait_with_signals(process)
@@ -356,9 +356,9 @@
     elif use_symbolization_script:
       # See above comment regarding offline symbolization.
       # Need to pipe to the symbolizer script.
-      p1 = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE,
-                            stderr=sys.stdout)
-      p2 = subprocess.Popen(
+      p1 = _popen(cmd, env=env, stdout=subprocess.PIPE,
+                  stderr=sys.stdout)
+      p2 = _popen(
           get_sanitizer_symbolize_command(executable_path=cmd[0]),
           env=env, stdin=p1.stdout)
       p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
@@ -375,6 +375,14 @@
     raise
 
 
+def _popen(*args, **kwargs):
+  assert 'creationflags' not in kwargs
+  if sys.platform == 'win32':
+    # Necessary for signal handling. See crbug.com/733612#c6.
+    kwargs['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP
+  return subprocess.Popen(*args, **kwargs)
+
+
 def main():
   return run_executable(sys.argv[1:], os.environ.copy())
 
diff --git a/testing/test_env_test_script.py b/testing/test_env_test_script.py
new file mode 100755
index 0000000..d6cd7197
--- /dev/null
+++ b/testing/test_env_test_script.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+# 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.
+
+"""Script for use in test_env unittests."""
+
+import os
+import signal
+import sys
+import time
+
+
+def print_signal(sig, *_):
+  print 'Signal :{}'.format(sig)
+
+
+if __name__ == '__main__':
+  signal.signal(signal.SIGTERM, print_signal)
+  signal.signal(signal.SIGINT, print_signal)
+  if sys.platform == 'win32':
+    signal.signal(signal.SIGBREAK, print_signal)
+  time.sleep(2)  # gives process time to receive signal.
diff --git a/testing/test_env_unittest.py b/testing/test_env_unittest.py
new file mode 100755
index 0000000..76d5766
--- /dev/null
+++ b/testing/test_env_unittest.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+# 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.
+
+"""Unit tests for test_env.py functionality.
+
+Each unit test is launches python process that uses test_env.py
+to launch another python process. Then signal handling and
+propagation is tested. This similates how Swarming uses test_env.py.
+"""
+
+import os
+import signal
+import subprocess
+import sys
+import time
+import unittest
+
+
+TEST_SCRIPT = 'test_env_user_script.py'
+
+
+def launch_process_windows(args):
+  return subprocess.Popen(
+      [sys.executable, TEST_SCRIPT] + args, stdout=subprocess.PIPE,
+      stderr=subprocess.STDOUT, env=os.environ.copy(),
+      creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
+
+def launch_process_nonwindows(args):
+  return subprocess.Popen(
+      [sys.executable, TEST_SCRIPT] + args, stdout=subprocess.PIPE,
+      stderr=subprocess.STDOUT, env=os.environ.copy())
+
+
+def read_subprocess_message(proc, starts_with):
+  """Finds the value after first line prefix condition."""
+  for line in proc.stdout:
+    if line.startswith(starts_with):
+      return line.rstrip().replace(starts_with, '')
+
+
+def send_and_wait(proc, sig, sleep_time=0.3):
+  """Sends a signal to subprocess."""
+  time.sleep(sleep_time)  # gives process time to launch.
+  os.kill(proc.pid, sig)
+  proc.wait()
+
+
+class SignalingWindowsTest(unittest.TestCase):
+
+  def setUp(self):
+    super(SignalingWindowsTest, self).setUp()
+    if sys.platform != 'win32':
+      self.skipTest('test only runs on Windows')
+
+  def test_send_ctrl_break_event(self):
+    proc = launch_process_windows([])
+    send_and_wait(proc, signal.CTRL_BREAK_EVENT)
+    sig = read_subprocess_message(proc, 'Signal :')
+    self.assertEqual(sig, str(signal.SIGBREAK))
+
+
+class SignalingNonWindowsTest(unittest.TestCase):
+
+  def setUp(self):
+    super(SignalingNonWindowsTest, self).setUp()
+    if sys.platform == 'win32':
+      self.skipTest('test does not run on Windows')
+
+  def test_send_sigterm(self):
+    proc = launch_process_nonwindows([])
+    send_and_wait(proc, signal.SIGTERM)
+    sig = read_subprocess_message(proc, 'Signal :')
+    self.assertEqual(sig, str(signal.SIGTERM))
+
+  def test_send_sigint(self):
+    proc = launch_process_nonwindows([])
+    send_and_wait(proc, signal.SIGINT)
+    sig = read_subprocess_message(proc, 'Signal :')
+    self.assertEqual(sig, str(signal.SIGINT))
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/testing/test_env_user_script.py b/testing/test_env_user_script.py
new file mode 100755
index 0000000..8cf70ad
--- /dev/null
+++ b/testing/test_env_user_script.py
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+# 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.
+
+"""Script for use in test_env unittests."""
+
+import test_env
+
+
+if __name__ == '__main__':
+  test_env.run_command(['python', 'test_env_test_script.py'])
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 200638c..678bd901 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -188,6 +188,16 @@
 const base::Feature kWebRtcHWH264Encoding{"WebRtcHWH264Encoding",
                                           base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Enables negotiation of experimental multiplex codec in SDP.
+const base::Feature kWebRtcMultiplexCodec{"WebRTC-MultiplexCodec",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Causes WebRTC to replace host ICE candidate IP addresses with generated
+// names ending in ".local" and resolve them using mDNS.
+// http://crbug.com/878465
+const base::Feature kWebRtcHideLocalIpsWithMdns{
+    "WebRtcHideLocalIpsWithMdns", base::FEATURE_ENABLED_BY_DEFAULT};
+
 #if BUILDFLAG(RTC_USE_H264) && BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS)
 // Run-time feature for the |rtc_use_h264| encoder/decoder.
 const base::Feature kWebRtcH264WithOpenH264FFmpeg{
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index f9ebdf8..6ae48b6 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -551,6 +551,7 @@
     "//services/network/public/mojom",
     "//third_party/blink/renderer/platform/wtf:wtf",
     "//third_party/webrtc/api:libjingle_peerconnection_api",
+    "//third_party/webrtc/api:rtc_error",
     "//third_party/webrtc/api:rtc_stats_api",
     "//third_party/webrtc/api:rtp_parameters",
     "//third_party/webrtc/api:scoped_refptr",
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index e595e75..29ee3bc 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -49,6 +49,8 @@
 BLINK_COMMON_EXPORT extern const base::Feature kWebRtcHWH264Encoding;
 BLINK_COMMON_EXPORT extern const base::Feature kWebRtcHWVP8Encoding;
 BLINK_COMMON_EXPORT extern const base::Feature kWebRtcHWVP9Encoding;
+BLINK_COMMON_EXPORT extern const base::Feature kWebRtcMultiplexCodec;
+BLINK_COMMON_EXPORT extern const base::Feature kWebRtcHideLocalIpsWithMdns;
 
 #if BUILDFLAG(RTC_USE_H264) && BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS)
 BLINK_COMMON_EXPORT extern const base::Feature kWebRtcH264WithOpenH264FFmpeg;
diff --git a/third_party/blink/public/mojom/payments/payment_app.mojom b/third_party/blink/public/mojom/payments/payment_app.mojom
index 4b88899..51762baf 100644
--- a/third_party/blink/public/mojom/payments/payment_app.mojom
+++ b/third_party/blink/public/mojom/payments/payment_app.mojom
@@ -50,6 +50,13 @@
   array<BasicCardType> supported_types;
 };
 
+enum PaymentDelegation {
+  SHIPPING_ADDRESS,
+  PAYER_NAME,
+  PAYER_PHONE,
+  PAYER_EMAIL,
+};
+
 // This interface provides implementation of PaymentInstruments.idl
 // and PaymentManager.idl in render side. This interface is implemented
 // by payment_manager.cc and runs in browser side.
@@ -72,6 +79,11 @@
   ClearPaymentInstruments()
       => (PaymentHandlerStatus status);
   SetUserHint(string user_hint);
+  // A method from PaymentManager.idl which lets payment handlers specify
+  // whether or not they can handle shipping address or contact info (payer's
+  // name/email/phone).
+  EnableDelegations(array<PaymentDelegation> delegations)
+     =>(PaymentHandlerStatus status);
 };
 
 // This struct is provided to send payment request data to render side
diff --git a/third_party/blink/public/platform/TaskTypes.md b/third_party/blink/public/platform/TaskTypes.md
index ce7ef0e..76c519a 100644
--- a/third_party/blink/public/platform/TaskTypes.md
+++ b/third_party/blink/public/platform/TaskTypes.md
@@ -1,68 +1,58 @@
-# Task Queues
+# Frame Associated Task Types
 
-Blink uses a series of task queues.
+Blink uses a series of task types defined in
+[task_type.h](https://cs.chromium.org/chromium/src/third_party/blink/public/platform/task_type.h).
+For each task type that can be frame-attributed, the table below indicates
+whether the task queue associated with this task type can be paused, throttled,
+frozen or deferred. All specified (in W3C, HTML, DOM, etc) task types are
+pausable. Some internal task queues are not.
 
-All specified (in W3C, HTML, DOM, etc) task queues are pausable. Some internal task queues are not.
-
-| Task Queue           | Pausable | Throttlable |     Frozen   | Deferred |
-| -------------------- | -------- | ----------- | ------------ | -------- |
-| DOM Manipulation     | Yes      | Yes         | Android Only |  Yes     |
-| User Interaction     | Yes      | Yes         | Android Only |  No      |
-| Networking           | Yes      | No          | Yes          |  Yes     |
-| Networking (URL Ldr) | Yes      | No          | Yes          |  Yes     |
-| Networking (Ctrl)    | Yes      | No          | Yes          |  Yes     |
-| History Traversal    | Yes      | Yes         | Android Only |  Yes     |
-| Embed                | Yes      | Yes         | Android Only |  Yes     |
-| Media Element        | Yes      | Yes         | Android Only |  No      |
-| Canvas Block Serial. | Yes      | Yes         | Android Only |  Yes     |
-| Microtask            | Yes      | Yes         | Android Only |  Yes     |
-| Javascript Timer     | Yes      | Yes         | Yes          |  Yes     |
-| Remote Event         | Yes      | Yes         | Android Only |  Yes     |
-| Web Socket           | Yes      | Yes         | Android Only |  Yes     |
-| Posted Message       | Yes      | Yes         | Android Only |  No      |
-| Unshipped Port Msg.  | Yes      | Yes         | Android Only |  Yes     |
-| File Reading         | Yes      | Yes         | Android Only |  Yes     |
-| Database Access      | Yes      | Yes         | Android Only |  No      |
-| Presentation         | Yes      | Yes         | Android Only |  Yes     |
-| Sensor               | Yes      | Yes         | Android Only |  Yes     |
-| Performance Timeline | Yes      | Yes         | Android Only |  Yes     |
-| WebGL                | Yes      | Yes         | Android Only |  Yes     |
-| Idle Task            | Yes      | Yes         | Android Only |  Yes     |
-| Misc Platform API    | Yes      | Yes         | Android Only |  Yes     |
-| Worker Animation     | Yes      | Yes         | Android Only |  No      |
-| Web Schdlr User Int. | Yes      | Yes         | Yes          |  No      |
-| Web Schdlr Best Eff. | Yes      | Yes         | Yes          |  Yes     |
-| Font Loading         | Yes      | Yes         | Android Only |  Yes     |
-| Application Lifecycle| Yes      | Yes         | Android Only |  Yes     |
-| Background Fetch     | Yes      | Yes         | Android Only |  Yes     |
-| Permission           | Yes      | Yes         | Android Only |  Yes     |
-| Service Worklet CMsg | Yes      | Yes         | Android Only |  No      |
-| Internal Default     | No       | No          | No           |  No      |
-| Internal Loading     | No       | No          | No           |  No      |
-| Internal Test        | No       | No          | No           |  No      |
-| Internal Web Crypto  | Yes      | Yes         | Android Only |  No      |
-| Internal Media       | Yes      | Yes         | Android Only |  No      |
-| Internal Media Rt.   | Yes      | Yes         | Android Only |  No      |
-| Internal IPC         | No       | No          | No           |  No      |
-| Internal User Inter. | Yes      | Yes         | Android Only |  No      |
-| Internal Inspector   | No       | No          | No           |  No      |
-| Internal Worker      | No       | No          | No           |  No      |
-| Internal Translation | No       | No          | No           |  No      |
-| Internal Intersec Obs| Yes      | Yes         | Android Only |  No      |
-| Internal Content Cpt | Yes      | Yes         | Yes          | Yes      |
-| Internal Nav         | No       | No          | No           |  No      |
-| Main Thread V8       | No       | No          | No           |  No      |
-| Main Thread Composit.| No       | No          | No           |  No      |
-| Main Thread Default  | No       | No          | No           |  No      |
-| Main Thread Input    | No       | No          | No           |  No      |
-| Main Thread Idle     | No       | No          | No           |  No      |
-| Main Thread Control  | No       | No          | No           |  No      |
-| Main Thread Cleanup  | No       | No          | No           |  No      |
-| Main Thread Mem Purge| No       | No          | No           |  No      |
-| Compositor Default   | No       | No          | No           |  No      |
-| Compositor Input     | No       | No          | No           |  No      |
-| Worker Default       | No       | No          | No           |  No      |
-| Worker V8            | No       | No          | No           |  No      |
-| Worker Compositor    | No       | No          | No           |  No      |
+| Queue Type                   | Throttlable | Deferrable | Freezable | Pausable | Virtual time |
+|------------------------------|-------------|------------|-----------|----------|--------------|
+| DOMManipulation              | No          | Yes        | Yes       | Yes      | Yes          |
+| UserInteraction              | No          | No         | Yes       | Yes      | Yes          |
+| Networking                   | No          | Yes        | Yes       | Yes      | No           |
+| NetworkingWithURLLoaderAnnot | No          | Yes        | Yes       | Yes      | No           |
+| NetworkingControl            | No          | Yes        | Yes       | Yes      | No           |
+| HistoryTraversal             | No          | Yes        | Yes       | Yes      | Yes          |
+| Embed                        | No          | Yes        | Yes       | Yes      | Yes          |
+| MediaElementEvent            | No          | No         | Yes       | Yes      | Yes          |
+| CanvasBlobSerialization      | No          | Yes        | Yes       | Yes      | Yes          |
+| Microtask                    | No          | Yes        | Yes       | Yes      | Yes          |
+| JavascriptTimer              | Yes         | Yes        | Yes       | Yes      | Yes          |
+| RemoteEvent                  | No          | Yes        | Yes       | Yes      | Yes          |
+| WebSocket                    | No          | Yes        | Yes       | Yes      | Yes          |
+| PostedMessage                | No          | No         | Yes       | Yes      | Yes          |
+| UnshippedPortMessage         | No          | Yes        | Yes       | Yes      | Yes          |
+| FileReading                  | No          | Yes        | Yes       | Yes      | Yes          |
+| DatabaseAccess               | No          | No         | Yes       | Yes      | Yes          |
+| Presentation                 | No          | Yes        | Yes       | Yes      | Yes          |
+| Sensor                       | No          | Yes        | Yes       | Yes      | Yes          |
+| PerformanceTimeline          | No          | Yes        | Yes       | Yes      | Yes          |
+| WebGL                        | No          | Yes        | Yes       | Yes      | Yes          |
+| IdleTask                     | No          | Yes        | Yes       | Yes      | Yes          |
+| MiscPlatformAPI              | No          | Yes        | Yes       | Yes      | Yes          |
+| WorkerAnimation              | No          | No         | Yes       | Yes      | Yes          |
+| FontLoading                  | No          | Yes        | Yes       | Yes      | Yes          |
+| ApplicationLifeCycle         | No          | Yes        | Yes       | Yes      | Yes          |
+| BackgroundFetch              | No          | Yes        | Yes       | Yes      | Yes          |
+| Permission                   | No          | Yes        | Yes       | Yes      | Yes          |
+| ServiceWorkerClientMessage   | No          | No         | Yes       | Yes      | Yes          |
+| WebLocks                     | No          | No         | No        | No       | Yes          |
+| InternalDefault              | No          | Yes        | Yes       | Yes      | Yes          |
+| InternalLoading              | No          | Yes        | Yes       | Yes      | No           |
+| InternalTest                 | No          | No         | No        | No       | Yes          |
+| InternalWebCrypto            | No          | No         | Yes       | Yes      | Yes          |
+| InternalMedia                | No          | No         | Yes       | Yes      | Yes          |
+| InternalMediaRealTime        | No          | No         | Yes       | Yes      | Yes          |
+| InternalIPC                  | No          | No         | No        | No       | Yes          |
+| InternalUserInteraction      | No          | No         | Yes       | Yes      | Yes          |
+| InternalInspector            | No          | No         | No        | No       | No           |
+| InternalTranslation          | Yes         | Yes        | Yes       | Yes      | Yes          |
+| InternalIntersectionObserver | No          | No         | Yes       | Yes      | Yes          |
+| InternalContentCapture       | Yes         | Yes        | Yes       | Yes      | Yes          |
+| InternalNavigationAssociated | No          | No         | No        | No       | No           |
+| InternalFreezableIPC         | No          | No         | Yes       | No       | No           |
+| InternalContinueScriptLoadin | No          | No         | Yes       | Yes      | Yes          |
 
 Internal Translation queue supports concept of it running only in the foreground. It is disabled if the page that owns it goes in background.
diff --git a/third_party/blink/public/platform/web_url_request.h b/third_party/blink/public/platform/web_url_request.h
index 9fb3898..7a7c680 100644
--- a/third_party/blink/public/platform/web_url_request.h
+++ b/third_party/blink/public/platform/web_url_request.h
@@ -35,16 +35,16 @@
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "base/unguessable_token.h"
-#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
-#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
 #include "third_party/blink/public/platform/web_common.h"
 #include "ui/base/page_transition_types.h"
 
+// TODO(crbug.com/922875): Need foo.mojom.shared-forward.h.
 namespace network {
 namespace mojom {
 enum class CorsPreflightPolicy : int32_t;
 enum class CredentialsMode : int32_t;
 enum class RedirectMode : int32_t;
+enum class ReferrerPolicy : int32_t;
 enum class RequestMode : int32_t;
 enum class RequestContextFrameType : int32_t;
 }  // namespace mojom
@@ -54,6 +54,7 @@
 
 namespace mojom {
 enum class FetchCacheMode : int32_t;
+enum class RequestContextType : int32_t;
 }  // namespace mojom
 
 class ResourceRequest;
@@ -153,7 +154,9 @@
     virtual ~ExtraData() = default;
 
    protected:
-    int render_frame_id_ = MSG_ROUTING_NONE;
+    BLINK_PLATFORM_EXPORT ExtraData();
+
+    int render_frame_id_;
     bool is_main_frame_ = false;
     ui::PageTransition transition_type_ = ui::PAGE_TRANSITION_LINK;
     bool is_for_no_state_prefetch_ = false;
diff --git a/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc b/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc
index 5cfbbd67..14a9707 100644
--- a/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc
+++ b/third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map_test.cc
@@ -12,8 +12,10 @@
 #include "third_party/blink/renderer/core/css/css_test_helpers.h"
 #include "third_party/blink/renderer/core/css/cssom/css_keyword_value.h"
 #include "third_party/blink/renderer/core/css/cssom/css_unit_value.h"
+#include "third_party/blink/renderer/core/css/cssom/css_unparsed_value.h"
 #include "third_party/blink/renderer/core/css/cssom/css_unsupported_color_value.h"
 #include "third_party/blink/renderer/core/css/cssom/paint_worklet_input.h"
+#include "third_party/blink/renderer/core/css/properties/longhands/custom_property.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/testing/page_test_base.h"
@@ -47,6 +49,27 @@
     waitable_event.Wait();
   }
 
+  void CheckUnregisteredProperty(base::WaitableEvent* waitable_event,
+                                 scoped_refptr<PaintWorkletInput> input) {
+    ASSERT_TRUE(!IsMainThread());
+
+    PaintWorkletStylePropertyMap* map =
+        MakeGarbageCollected<PaintWorkletStylePropertyMap>(
+            input->StyleMapData());
+    ASSERT_TRUE(map);
+
+    const PaintWorkletStylePropertyMap::CrossThreadData& data =
+        map->StyleMapDataForTest();
+    EXPECT_EQ(data.size(), 1u);
+    EXPECT_EQ(data.at("--x")->GetType(),
+              CrossThreadStyleValue::StyleValueType::kUnparsedType);
+    CSSStyleValue* style_value = data.at("--x")->ToCSSStyleValue();
+    EXPECT_EQ(style_value->GetType(),
+              CSSStyleValue::StyleValueType::kUnparsedType);
+    EXPECT_EQ(static_cast<CSSUnparsedValue*>(style_value)->ToString(), "50");
+    waitable_event->Signal();
+  }
+
   void CheckCrossThreadData(base::WaitableEvent* waitable_event,
                             scoped_refptr<PaintWorkletInput> input) {
     DCHECK(!IsMainThread());
@@ -87,6 +110,46 @@
   std::unique_ptr<blink::Thread> thread_;
 };
 
+TEST_F(PaintWorkletStylePropertyMapTest, UnregisteredCustomProperty) {
+  CustomProperty property("--x", GetDocument());
+  Vector<CSSPropertyID> native_properties;
+  Vector<AtomicString> custom_properties({"--x"});
+
+  GetDocument().documentElement()->SetInnerHTMLFromString(
+      "<div id='target' style='--x:50'></div>");
+  UpdateAllLifecyclePhasesForTest();
+
+  Element* node = GetDocument().getElementById("target");
+  node->GetLayoutObject()->GetMutableForPainting().EnsureId();
+  CompositorPaintWorkletInput::PropertyKeys input_property_keys;
+  auto data = PaintWorkletStylePropertyMap::BuildCrossThreadData(
+      GetDocument(), node->GetLayoutObject()->UniqueId(),
+      node->ComputedStyleRef(), native_properties, custom_properties,
+      input_property_keys);
+  EXPECT_TRUE(data.has_value());
+
+  Vector<std::unique_ptr<CrossThreadStyleValue>> input_arguments;
+  std::vector<cc::PaintWorkletInput::PropertyKey> property_keys;
+  scoped_refptr<PaintWorkletInput> input =
+      base::MakeRefCounted<PaintWorkletInput>(
+          "test", FloatSize(100, 100), 1.0f, 1.0f, 1, std::move(data.value()),
+          std::move(input_arguments), std::move(property_keys));
+  ASSERT_TRUE(input);
+
+  thread_ = blink::Thread::CreateThread(
+      ThreadCreationParams(WebThreadType::kTestThread).SetSupportsGC(true));
+  base::WaitableEvent waitable_event;
+  PostCrossThreadTask(
+      *thread_->GetTaskRunner(), FROM_HERE,
+      CrossThreadBindOnce(
+          &PaintWorkletStylePropertyMapTest::CheckUnregisteredProperty,
+          CrossThreadUnretained(this), CrossThreadUnretained(&waitable_event),
+          std::move(input)));
+  waitable_event.Wait();
+
+  ShutDownThread();
+}
+
 TEST_F(PaintWorkletStylePropertyMapTest, CreateSupportedCrossThreadData) {
   Vector<CSSPropertyID> native_properties({CSSPropertyID::kDisplay});
   Vector<AtomicString> custom_properties({"--foo", "--bar", "--loo", "--gar"});
diff --git a/third_party/blink/renderer/core/dom/slot_assignment.cc b/third_party/blink/renderer/core/dom/slot_assignment.cc
index e2cb16f9..84c5c69 100644
--- a/third_party/blink/renderer/core/dom/slot_assignment.cc
+++ b/third_party/blink/renderer/core/dom/slot_assignment.cc
@@ -26,7 +26,7 @@
     return HTMLDetailsElement::IsFirstSummary(node);
   if (IsHTMLSelectElement(node.parentElement()))
     return HTMLSelectElement::CanAssignToSelectSlot(node);
-  if (IsHTMLOptGroupElement(node.parentElement()))
+  if (IsA<HTMLOptGroupElement>(node.parentElement()))
     return HTMLOptGroupElement::CanAssignToOptGroupSlot(node);
   return false;
 }
diff --git a/third_party/blink/renderer/core/editing/element_inner_text.cc b/third_party/blink/renderer/core/editing/element_inner_text.cc
index a55f934e..c803623e 100644
--- a/third_party/blink/renderer/core/editing/element_inner_text.cc
+++ b/third_party/blink/renderer/core/editing/element_inner_text.cc
@@ -360,7 +360,7 @@
 
   // 9. If node is a p element, then append 2 (a required line break count) at
   // the beginning and end of items.
-  if (IsHTMLParagraphElement(node)) {
+  if (IsA<HTMLParagraphElement>(node)) {
     // Note: <p style="display:contents>foo</p> doesn't generate layout object
     // for P.
     ProcessChildrenWithRequiredLineBreaks(node, 2);
@@ -390,7 +390,7 @@
       ProcessOptionElement(ToHTMLOptionElement(child));
       continue;
     }
-    if (!IsHTMLOptGroupElement(child))
+    if (!IsA<HTMLOptGroupElement>(child))
       continue;
     // Note: We should emit newline for OPTGROUP even if it has no OPTION.
     // e.g. <div>a<select><optgroup></select>b</div>.innerText == "a\nb"
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator.cc b/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
index 31fd9b8..d25e2ef 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
+++ b/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
@@ -28,6 +28,7 @@
 #include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
 
 #include <unicode/utf16.h>
+#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
@@ -310,10 +311,13 @@
       node_ = nullptr;
       return;
     }
+    const bool locked =
+        DisplayLockUtilities::NearestLockedInclusiveAncestor(*node_);
 
     LayoutObject* layout_object = node_->GetLayoutObject();
-    if (!layout_object) {
-      if (IsA<ShadowRoot>(node_.Get()) || HasDisplayContents(*node_)) {
+    if (!layout_object || locked) {
+      if (!locked &&
+          (IsA<ShadowRoot>(node_.Get()) || HasDisplayContents(*node_))) {
         // Shadow roots or display: contents elements don't have LayoutObjects,
         // but we want to visit children anyway.
         iteration_progress_ = iteration_progress_ < kHandledNode
@@ -612,7 +616,7 @@
 
   // Need to make an exception for option and optgroup, because we want to
   // keep the legacy behavior before we added layoutObjects to them.
-  if (IsHTMLOptionElement(node) || IsHTMLOptGroupElement(node))
+  if (IsHTMLOptionElement(node) || IsA<HTMLOptGroupElement>(node))
     return false;
 
   // Need to make an exception for table cells, because they are blocks, but we
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc b/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc
index 004aeee..1bfddc2c 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc
+++ b/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc
@@ -32,6 +32,7 @@
 
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
+#include "third_party/blink/renderer/core/editing/position.h"
 #include "third_party/blink/renderer/core/editing/selection_template.h"
 #include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
@@ -1030,5 +1031,16 @@
   EXPECT_EQ("[foo  bar]", Iterate<DOMTree>(EmitsSpaceForNbspBehavior()));
 }
 
+TEST_P(TextIteratorTest, IterateWithLockedSubtree) {
+  SetBodyContent("<div id='parent'>foo<div id='locked'>text</div>bar</div>");
+  auto* locked = GetDocument().getElementById("locked");
+  locked->setAttribute("rendersubtree", "invisible activatable");
+  GetDocument().UpdateStyleAndLayout();
+  auto* parent = GetDocument().getElementById("parent");
+  const Position start_position = Position::FirstPositionInNode(*parent);
+  const Position end_position = Position::LastPositionInNode(*parent);
+  EXPECT_EQ(6, TextIterator::RangeLength(start_position, end_position));
+}
+
 }  // namespace text_iterator_test
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/execution_context/security_context.cc b/third_party/blink/renderer/core/execution_context/security_context.cc
index dff9450..0a96919 100644
--- a/third_party/blink/renderer/core/execution_context/security_context.cc
+++ b/third_party/blink/renderer/core/execution_context/security_context.cc
@@ -27,6 +27,7 @@
 #include "third_party/blink/renderer/core/execution_context/security_context.h"
 
 #include "base/metrics/histogram_macros.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/common/feature_policy/feature_policy.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
diff --git a/third_party/blink/renderer/core/fetch/blob_bytes_consumer_test.cc b/third_party/blink/renderer/core/fetch/blob_bytes_consumer_test.cc
index 21c35e3..308fe7de 100644
--- a/third_party/blink/renderer/core/fetch/blob_bytes_consumer_test.cc
+++ b/third_party/blink/renderer/core/fetch/blob_bytes_consumer_test.cc
@@ -4,7 +4,8 @@
 
 #include "third_party/blink/renderer/core/fetch/blob_bytes_consumer.h"
 
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/fetch/bytes_consumer_test_util.h"
 #include "third_party/blink/renderer/core/loader/threadable_loader.h"
@@ -43,10 +44,10 @@
  public:
   void SetUp() override { PageTestBase::SetUp(IntSize(1, 1)); }
   scoped_refptr<BlobDataHandle> CreateBlob(const String& body) {
-    mojom::blink::BlobPtrInfo mojo_blob;
-    mojo::MakeStrongBinding(
+    mojo::PendingRemote<mojom::blink::Blob> mojo_blob;
+    mojo::MakeSelfOwnedReceiver(
         std::make_unique<FakeBlob>(kBlobUUID, body, &blob_state_),
-        MakeRequest(&mojo_blob));
+        mojo_blob.InitWithNewPipeAndPassReceiver());
     return BlobDataHandle::Create(kBlobUUID, "", body.length(),
                                   std::move(mojo_blob));
   }
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
index 5027d13..a7cd502 100644
--- a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
+++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
@@ -283,9 +283,10 @@
 
   // Receiving more data than expected would indicate a bug in the
   // implementation of the mojom Blob interface. However there is no guarantee
-  // that the BlobPtr is actually backed by a "real" blob, so to defend against
-  // compromised renderer processes we still need to carefully validate anything
-  // received. So return an error if we received too much data.
+  // that the Blob is actually backed by a "real" blob, so to
+  // defend against compromised renderer processes we still need to carefully
+  // validate anything received. So return an error if we received too much
+  // data.
   if (bytes_loaded_ + data_length > raw_data_.DataLength()) {
     raw_data_.reset();
     bytes_loaded_ = 0;
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 999a61a1..281838c 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -289,7 +289,13 @@
     return nullptr;
   }
 
-  context_ = factory->Create(this, attributes);
+  // If this context is cross-origin, it should prefer to use the low-power GPU
+  LocalFrame* frame = GetDocument().GetFrame();
+  CanvasContextCreationAttributesCore recomputed_attributes = attributes;
+  if (frame && frame->IsCrossOriginSubframe())
+    recomputed_attributes.power_preference = "low-power";
+
+  context_ = factory->Create(this, recomputed_attributes);
   if (!context_)
     return nullptr;
 
diff --git a/third_party/blink/renderer/core/html/forms/external_popup_menu.cc b/third_party/blink/renderer/core/html/forms/external_popup_menu.cc
index c640df4..9253ddc 100644
--- a/third_party/blink/renderer/core/html/forms/external_popup_menu.cc
+++ b/third_party/blink/renderer/core/html/forms/external_popup_menu.cc
@@ -254,7 +254,7 @@
     popup_item.checked = false;
     if (IsA<HTMLHRElement>(item_element)) {
       popup_item.type = WebMenuItemInfo::kSeparator;
-    } else if (IsHTMLOptGroupElement(item_element)) {
+    } else if (IsA<HTMLOptGroupElement>(item_element)) {
       popup_item.type = WebMenuItemInfo::kGroup;
     } else {
       popup_item.type = WebMenuItemInfo::kOption;
diff --git a/third_party/blink/renderer/core/html/forms/html_option_element.cc b/third_party/blink/renderer/core/html/forms/html_option_element.cc
index a79c57e..3dd52b8 100644
--- a/third_party/blink/renderer/core/html/forms/html_option_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_option_element.cc
@@ -282,7 +282,7 @@
     return nullptr;
   if (auto* select = ToHTMLSelectElementOrNull(*parentNode()))
     return select;
-  if (IsHTMLOptGroupElement(*parentNode()))
+  if (IsA<HTMLOptGroupElement>(*parentNode()))
     return ToHTMLSelectElementOrNull(parentNode()->parentNode());
   return nullptr;
 }
@@ -302,7 +302,7 @@
 
 String HTMLOptionElement::TextIndentedToRespectGroupLabel() const {
   ContainerNode* parent = parentNode();
-  if (parent && IsHTMLOptGroupElement(*parent))
+  if (parent && IsA<HTMLOptGroupElement>(*parent))
     return "    " + DisplayLabel();
   return DisplayLabel();
 }
@@ -315,7 +315,7 @@
   if (OwnElementDisabled())
     return true;
   if (Element* parent = parentElement())
-    return IsHTMLOptGroupElement(*parent) && parent->IsDisabledFormControl();
+    return IsA<HTMLOptGroupElement>(*parent) && parent->IsDisabledFormControl();
   return false;
 }
 
@@ -329,8 +329,9 @@
     ContainerNode& insertion_point) {
   HTMLElement::InsertedInto(insertion_point);
   if (HTMLSelectElement* select = OwnerSelectElement()) {
-    if (&insertion_point == select || (IsHTMLOptGroupElement(insertion_point) &&
-                                       insertion_point.parentNode() == select))
+    if (&insertion_point == select ||
+        (IsA<HTMLOptGroupElement>(insertion_point) &&
+         insertion_point.parentNode() == select))
       select->OptionInserted(*this, is_selected_);
   }
   return kInsertionDone;
@@ -338,9 +339,9 @@
 
 void HTMLOptionElement::RemovedFrom(ContainerNode& insertion_point) {
   if (auto* select = ToHTMLSelectElementOrNull(insertion_point)) {
-    if (!parentNode() || IsHTMLOptGroupElement(*parentNode()))
+    if (!parentNode() || IsA<HTMLOptGroupElement>(*parentNode()))
       select->OptionRemoved(*this);
-  } else if (IsHTMLOptGroupElement(insertion_point)) {
+  } else if (IsA<HTMLOptGroupElement>(insertion_point)) {
     select = ToHTMLSelectElementOrNull(insertion_point.parentNode());
     if (select)
       select->OptionRemoved(*this);
diff --git a/third_party/blink/renderer/core/html/forms/html_options_collection.h b/third_party/blink/renderer/core/html/forms/html_options_collection.h
index 45fd818..05161b17 100644
--- a/third_party/blink/renderer/core/html/forms/html_options_collection.h
+++ b/third_party/blink/renderer/core/html/forms/html_options_collection.h
@@ -76,7 +76,8 @@
     return false;
   if (parent == &RootNode())
     return true;
-  return IsHTMLOptGroupElement(*parent) && parent->parentNode() == &RootNode();
+  return IsA<HTMLOptGroupElement>(*parent) &&
+         parent->parentNode() == &RootNode();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.cc b/third_party/blink/renderer/core/html/forms/html_select_element.cc
index 84911d9c..24565b9 100644
--- a/third_party/blink/renderer/core/html/forms/html_select_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_select_element.cc
@@ -767,7 +767,7 @@
     // We should ignore nested optgroup elements. The HTML parser flatten
     // them.  However we need to ignore nested optgroups built by DOM APIs.
     // This behavior matches to IE and Firefox.
-    if (IsHTMLOptGroupElement(*current_html_element)) {
+    if (IsA<HTMLOptGroupElement>(*current_html_element)) {
       if (current_html_element->parentNode() != this) {
         current_element =
             ElementTraversal::NextSkippingChildren(*current_html_element, this);
@@ -1883,7 +1883,7 @@
 
 String HTMLSelectElement::ItemText(const Element& element) const {
   String item_string;
-  if (auto* optgroup = ToHTMLOptGroupElementOrNull(element))
+  if (auto* optgroup = DynamicTo<HTMLOptGroupElement>(element))
     item_string = optgroup->GroupLabelText();
   else if (auto* option = ToHTMLOptionElementOrNull(element))
     item_string = option->TextIndentedToRespectGroupLabel();
diff --git a/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc b/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
index 3cbc9678..e14fd70 100644
--- a/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
+++ b/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
@@ -268,11 +268,11 @@
   const HeapVector<Member<HTMLElement>>& items = owner_element.GetListItems();
   for (; context.list_index_ < items.size(); ++context.list_index_) {
     Element& child = *items[context.list_index_];
-    if (!IsHTMLOptGroupElement(child.parentNode()))
+    if (!IsA<HTMLOptGroupElement>(child.parentNode()))
       context.FinishGroupIfNecessary();
     if (auto* option = ToHTMLOptionElementOrNull(child))
       AddOption(context, *option);
-    else if (auto* optgroup = ToHTMLOptGroupElementOrNull(child))
+    else if (auto* optgroup = DynamicTo<HTMLOptGroupElement>(child))
       AddOptGroup(context, *optgroup);
     else if (auto* hr = ToHTMLHRElementOrNull(child))
       AddSeparator(context, *hr);
@@ -534,11 +534,11 @@
   const HeapVector<Member<HTMLElement>>& items = owner_element_->GetListItems();
   for (; context.list_index_ < items.size(); ++context.list_index_) {
     Element& child = *items[context.list_index_];
-    if (!IsHTMLOptGroupElement(child.parentNode()))
+    if (!IsA<HTMLOptGroupElement>(child.parentNode()))
       context.FinishGroupIfNecessary();
     if (auto* option = ToHTMLOptionElementOrNull(child))
       AddOption(context, *option);
-    else if (auto* optgroup = ToHTMLOptGroupElementOrNull(child))
+    else if (auto* optgroup = DynamicTo<HTMLOptGroupElement>(child))
       AddOptGroup(context, *optgroup);
     else if (auto* hr = ToHTMLHRElementOrNull(child))
       AddSeparator(context, *hr);
diff --git a/third_party/blink/renderer/core/html/forms/option_list.cc b/third_party/blink/renderer/core/html/forms/option_list.cc
index b6c0994..6c4b3f8 100644
--- a/third_party/blink/renderer/core/html/forms/option_list.cc
+++ b/third_party/blink/renderer/core/html/forms/option_list.cc
@@ -27,7 +27,7 @@
       current_ = option;
       return;
     }
-    if (IsHTMLOptGroupElement(current) &&
+    if (IsA<HTMLOptGroupElement>(current) &&
         current->parentNode() == select_.Get()) {
       if ((current_ = Traversal<HTMLOptionElement>::FirstChild(*current)))
         return;
diff --git a/third_party/blink/renderer/core/html/html_hr_element.cc b/third_party/blink/renderer/core/html/html_hr_element.cc
index b55a94c..4c00740d 100644
--- a/third_party/blink/renderer/core/html/html_hr_element.cc
+++ b/third_party/blink/renderer/core/html/html_hr_element.cc
@@ -114,7 +114,7 @@
     return nullptr;
   if (auto* select = ToHTMLSelectElementOrNull(*parentNode()))
     return select;
-  if (!IsHTMLOptGroupElement(*parentNode()))
+  if (!IsA<HTMLOptGroupElement>(*parentNode()))
     return nullptr;
   return ToHTMLSelectElementOrNull(parentNode()->parentNode());
 }
@@ -123,8 +123,9 @@
     ContainerNode& insertion_point) {
   HTMLElement::InsertedInto(insertion_point);
   if (HTMLSelectElement* select = OwnerSelectElement()) {
-    if (&insertion_point == select || (IsHTMLOptGroupElement(insertion_point) &&
-                                       insertion_point.parentNode() == select))
+    if (&insertion_point == select ||
+        (IsA<HTMLOptGroupElement>(insertion_point) &&
+         insertion_point.parentNode() == select))
       select->HrInsertedOrRemoved(*this);
   }
   return kInsertionDone;
@@ -132,9 +133,9 @@
 
 void HTMLHRElement::RemovedFrom(ContainerNode& insertion_point) {
   if (auto* select = ToHTMLSelectElementOrNull(insertion_point)) {
-    if (!parentNode() || IsHTMLOptGroupElement(*parentNode()))
+    if (!parentNode() || IsA<HTMLOptGroupElement>(*parentNode()))
       select->HrInsertedOrRemoved(*this);
-  } else if (IsHTMLOptGroupElement(insertion_point)) {
+  } else if (IsA<HTMLOptGroupElement>(insertion_point)) {
     Node* parent = insertion_point.parentNode();
     select = ToHTMLSelectElementOrNull(parent);
     if (select)
diff --git a/third_party/blink/renderer/core/layout/layout_list_box.cc b/third_party/blink/renderer/core/layout/layout_list_box.cc
index a505cc5..7802cb6 100644
--- a/third_party/blink/renderer/core/layout/layout_list_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_list_box.cc
@@ -93,7 +93,7 @@
 
   LayoutUnit max_height;
   for (Element* element : items) {
-    if (auto* optgroup = ToHTMLOptGroupElementOrNull(element))
+    if (auto* optgroup = DynamicTo<HTMLOptGroupElement>(element))
       element = &optgroup->OptGroupLabelElement();
     LayoutObject* layout_object = element->GetLayoutObject();
     LayoutUnit item_height;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
index 09d86e4..244d92a 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
@@ -821,14 +821,26 @@
 
   // BoxData contains inline boxes to be created later. Take them into account.
   for (const BoxData& box_data : box_data_list_) {
+    // Except when the box has `vertical-align: top` or `bottom`.
+    DCHECK(box_data.item->Style());
+    const ComputedStyle& style = *box_data.item->Style();
+    EVerticalAlign vertical_align = style.VerticalAlign();
+    if (vertical_align == EVerticalAlign::kTop ||
+        vertical_align == EVerticalAlign::kBottom)
+      continue;
+
     // |block_offset| is the top position when the baseline is at 0.
     LayoutUnit box_ascent =
         -line_box[box_data.fragment_end].offset.block_offset;
-    LayoutUnit box_descent = box_data.size.block_size - box_ascent;
+    NGLineHeightMetrics box_metrics(box_ascent,
+                                    box_data.size.block_size - box_ascent);
     // The top/bottom of inline boxes should not include their paddings.
-    box_ascent -= box_data.padding.line_over;
-    box_descent -= box_data.padding.line_under;
-    metrics.Unite(NGLineHeightMetrics(box_ascent, box_descent));
+    box_metrics.ascent -= box_data.padding.line_over;
+    box_metrics.descent -= box_data.padding.line_under;
+    // Include the line-height property. The inline box has the height of the
+    // font metrics without the line-height included.
+    box_metrics.AddLeading(style.ComputedLineHeightAsFixed());
+    metrics.Unite(box_metrics);
   }
 
   // In quirks mode, metrics is empty if no content.
diff --git a/third_party/blink/renderer/core/messaging/blink_transferable_message.cc b/third_party/blink/renderer/core/messaging/blink_transferable_message.cc
index 5416a89..23cf1cd8 100644
--- a/third_party/blink/renderer/core/messaging/blink_transferable_message.cc
+++ b/third_party/blink/renderer/core/messaging/blink_transferable_message.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 #include "mojo/public/cpp/base/big_buffer.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom-blink.h"
 #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
 #include "third_party/blink/renderer/platform/blob/blob_data.h"
@@ -130,8 +131,8 @@
     result.blobs.push_back(mojom::SerializedBlob::New(
         blob.value->Uuid().Utf8(), blob.value->GetType().Utf8(),
         blob.value->size(),
-        mojom::BlobPtrInfo(blob.value->CloneBlobRemote().PassPipe(),
-                           mojom::Blob::Version_)));
+        mojo::PendingRemote<mojom::Blob>(
+            blob.value->CloneBlobRemote().PassPipe(), mojom::Blob::Version_)));
   }
   result.stack_trace_id = message.sender_stack_trace_id.id;
   result.stack_trace_debugger_id_first =
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
index 102d549..6e8bbcd 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -243,7 +243,11 @@
       return nullptr;
     }
   } else {
-    context_ = factory->Create(this, attributes);
+    CanvasContextCreationAttributesCore recomputed_attributes = attributes;
+    if (!allow_high_performance_power_preference_)
+      recomputed_attributes.power_preference = "low-power";
+
+    context_ = factory->Create(this, recomputed_attributes);
   }
 
   return context_.Get();
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
index d4394c50..f9a9951 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
@@ -103,6 +103,10 @@
     filter_quality_ = quality;
   }
 
+  void AllowHighPerformancePowerPreference() {
+    allow_high_performance_power_preference_ = true;
+  }
+
   // CanvasRenderingContextHost implementation.
   void FinalizeFrame() override {}
   void DetachContext() override { context_ = nullptr; }
@@ -200,6 +204,11 @@
 
   SkFilterQuality filter_quality_ = kLow_SkFilterQuality;
 
+  // An offscreen canvas should only prefer the high-performance GPU if it is
+  // initialized by transferring control from an HTML canvas that is not
+  // cross-origin.
+  bool allow_high_performance_power_preference_ = false;
+
   // cc::FrameSinkId is broken into two integer components as this can be used
   // in transfer of OffscreenCanvas across threads
   // If this object is not created via
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index 30dcfb2..b41b2d36 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -474,6 +474,7 @@
     "//third_party/blink/renderer/platform",
     "//third_party/blink/renderer/platform/wtf",
     "//third_party/opus",
+    "//third_party/webrtc/api:rtc_error",
     "//third_party/webrtc/rtc_base:rtc_base",
     "//v8",
   ]
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index 5d3b329b..bd334a5 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -604,10 +604,10 @@
   if (IsHTMLProgressElement(*GetNode()))
     return ax::mojom::Role::kProgressIndicator;
 
-  if (IsHTMLOutputElement(*GetNode()))
+  if (IsA<HTMLOutputElement>(*GetNode()))
     return ax::mojom::Role::kStatus;
 
-  if (IsHTMLParagraphElement(*GetNode()))
+  if (IsA<HTMLParagraphElement>(*GetNode()))
     return ax::mojom::Role::kParagraph;
 
   if (IsA<HTMLLabelElement>(*GetNode()))
@@ -1189,7 +1189,7 @@
     return kRestrictionNone;
 
   // An <optgroup> is not exposed directly in the AX tree.
-  if (IsHTMLOptGroupElement(elem))
+  if (IsA<HTMLOptGroupElement>(elem))
     return kRestrictionNone;
 
   // According to ARIA, all elements of the base markup can be disabled.
diff --git a/third_party/blink/renderer/modules/accessibility/ax_selection_test.cc b/third_party/blink/renderer/modules/accessibility/ax_selection_test.cc
index c6c636b..4a10b2c 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_selection_test.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_selection_test.cc
@@ -302,7 +302,7 @@
 
   const Node* paragraph = GetDocument().QuerySelector("p");
   ASSERT_NE(nullptr, paragraph);
-  ASSERT_TRUE(IsHTMLParagraphElement(paragraph));
+  ASSERT_TRUE(IsA<HTMLParagraphElement>(paragraph));
   const Node* br = GetDocument().QuerySelector("br");
   ASSERT_NE(nullptr, br);
   ASSERT_TRUE(IsA<HTMLBRElement>(br));
@@ -347,7 +347,7 @@
 
   const Node* paragraph = GetDocument().QuerySelector("p");
   ASSERT_NE(nullptr, paragraph);
-  ASSERT_TRUE(IsHTMLParagraphElement(paragraph));
+  ASSERT_TRUE(IsA<HTMLParagraphElement>(paragraph));
   const Node* br = GetDocument().QuerySelector("br");
   ASSERT_NE(nullptr, br);
   ASSERT_TRUE(IsA<HTMLBRElement>(br));
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
index 092f5a3b..7a1464a 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
@@ -8,6 +8,7 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram_macros.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/request_or_usv_string.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/modules/v8/request_or_usv_string_or_request_or_usv_string_sequence.h"
diff --git a/third_party/blink/renderer/modules/bluetooth/bluetooth.cc b/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
index 5cdce3a..e85d4961 100644
--- a/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
+++ b/third_party/blink/renderer/modules/bluetooth/bluetooth.cc
@@ -149,7 +149,7 @@
   }
 
   CHECK(context->IsSecureContext());
-  EnsureServiceConnection();
+  EnsureServiceConnection(context);
 
   // Subsequent steps are handled in the browser process.
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
@@ -183,7 +183,12 @@
 ScriptPromise Bluetooth::requestDevice(ScriptState* script_state,
                                        const RequestDeviceOptions* options,
                                        ExceptionState& exception_state) {
-  ExecutionContext* context = ExecutionContext::From(script_state);
+  ExecutionContext* context = GetExecutionContext();
+  if (!context) {
+    return ScriptPromise::Reject(
+        script_state, V8ThrowException::CreateTypeError(
+                          script_state->GetIsolate(), kInactiveDocumentError));
+  }
 
 // Remind developers when they are using Web Bluetooth on unsupported platforms.
 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX) && \
@@ -216,7 +221,7 @@
             "Must be handling a user gesture to show a permission request."));
   }
 
-  EnsureServiceConnection();
+  EnsureServiceConnection(context);
 
   // In order to convert the arguments from service names and aliases to just
   // UUIDs, do the following substeps:
@@ -300,8 +305,12 @@
 ScriptPromise Bluetooth::requestLEScan(ScriptState* script_state,
                                        const BluetoothLEScanOptions* options,
                                        ExceptionState& exception_state) {
-  ExecutionContext* context = ExecutionContext::From(script_state);
-  DCHECK(context);
+  ExecutionContext* context = GetExecutionContext();
+  if (!context) {
+    return ScriptPromise::Reject(
+        script_state, V8ThrowException::CreateTypeError(
+                          script_state->GetIsolate(), kInactiveDocumentError));
+  }
 
   // Remind developers when they are using Web Bluetooth on unsupported
   // platforms.
@@ -332,7 +341,7 @@
             "Must be handling a user gesture to show a permission request."));
   }
 
-  EnsureServiceConnection();
+  EnsureServiceConnection(context);
 
   auto scan_options = mojom::blink::WebBluetoothRequestLEScanOptions::New();
   ConvertRequestLEScanOptions(options, scan_options, exception_state);
@@ -451,12 +460,9 @@
   return device;
 }
 
-void Bluetooth::EnsureServiceConnection() {
+void Bluetooth::EnsureServiceConnection(ExecutionContext* context) {
   if (!service_) {
     // See https://bit.ly/2S0zRAS for task types.
-    auto* context = GetExecutionContext();
-    DCHECK(context);
-
     auto task_runner = context->GetTaskRunner(TaskType::kMiscPlatformAPI);
     context->GetInterfaceProvider()->GetInterface(
         mojo::MakeRequest(&service_, task_runner));
diff --git a/third_party/blink/renderer/modules/bluetooth/bluetooth.h b/third_party/blink/renderer/modules/bluetooth/bluetooth.h
index ac56835..5a499b7e 100644
--- a/third_party/blink/renderer/modules/bluetooth/bluetooth.h
+++ b/third_party/blink/renderer/modules/bluetooth/bluetooth.h
@@ -77,7 +77,7 @@
                                mojo::BindingId id,
                                mojom::blink::RequestScanningStartResultPtr);
 
-  void EnsureServiceConnection();
+  void EnsureServiceConnection(ExecutionContext*);
 
   // Map of device ids to BluetoothDevice objects.
   // Ensures only one BluetoothDevice instance represents each
diff --git a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc
index c064aa7..7fe743a8 100644
--- a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc
+++ b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.h"
 
 #include "third_party/blink/renderer/core/dom/dom_node_ids.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
 #include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h"
 #include "third_party/blink/renderer/modules/canvas/htmlcanvas/canvas_context_creation_attributes_helpers.h"
@@ -67,6 +68,12 @@
       OffscreenCanvas::Create(canvas.width(), canvas.height());
   offscreen_canvas->SetFilterQuality(canvas.FilterQuality());
 
+  // If this canvas is cross-origin, then the associated offscreen canvas
+  // should prefer using the low-power GPU.
+  LocalFrame* frame = canvas.GetDocument().GetFrame();
+  if (!(frame && frame->IsCrossOriginSubframe()))
+    offscreen_canvas->AllowHighPerformancePowerPreference();
+
   DOMNodeId canvas_id = DOMNodeIds::IdForNode(&canvas);
   offscreen_canvas->SetPlaceholderCanvasId(canvas_id);
   canvas.RegisterPlaceholderCanvas(static_cast<int>(canvas_id));
diff --git a/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc b/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc
index b897257f..59866c6b 100644
--- a/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc
+++ b/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc
@@ -6,6 +6,7 @@
 
 #include "base/stl_util.h"
 #include "mojo/public/cpp/bindings/array_traits_wtf_vector.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/platform/file_path_conversion.h"
 #include "third_party/blink/public/platform/web_blob_info.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h"
@@ -207,7 +208,7 @@
     if (mime_type.IsNull())
       mime_type = g_empty_string;
     blob_info->mime_type = mime_type;
-    blob_info->blob = blink::mojom::blink::BlobPtrInfo(
+    blob_info->blob = mojo::PendingRemote<blink::mojom::blink::Blob>(
         info.CloneBlobHandle(), blink::mojom::blink::Blob::Version_);
     blob_or_file_info.push_back(std::move(blob_info));
   }
diff --git a/third_party/blink/renderer/modules/payments/payment_manager.cc b/third_party/blink/renderer/modules/payments/payment_manager.cc
index 0952de3..b41c340 100644
--- a/third_party/blink/renderer/modules/payments/payment_manager.cc
+++ b/third_party/blink/renderer/modules/payments/payment_manager.cc
@@ -6,6 +6,7 @@
 
 #include "services/service_manager/public/cpp/interface_provider.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/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/modules/payments/payment_instruments.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
@@ -34,9 +35,55 @@
   manager_->SetUserHint(user_hint_);
 }
 
+ScriptPromise PaymentManager::enableDelegations(
+    ScriptState* script_state,
+    const Vector<String>& stringified_delegations) {
+  if (!script_state->ContextIsValid()) {
+    return ScriptPromise::RejectWithDOMException(
+        script_state, MakeGarbageCollected<DOMException>(
+                          DOMExceptionCode::kInvalidStateError,
+                          "Cannot enable payment delegations"));
+  }
+
+  if (enable_delegations_resolver_) {
+    return ScriptPromise::RejectWithDOMException(
+        script_state, MakeGarbageCollected<DOMException>(
+                          DOMExceptionCode::kInvalidStateError,
+                          "Cannot call enableDelegations() again until "
+                          "the previous enableDelegations() is finished"));
+  }
+
+  Vector<payments::mojom::blink::PaymentDelegation> delegations;
+  for (auto delegation : stringified_delegations) {
+    if (delegation == "shippingAddress") {
+      delegations.emplace_back(
+          payments::mojom::blink::PaymentDelegation::SHIPPING_ADDRESS);
+    } else if (delegation == "payerName") {
+      delegations.emplace_back(
+          payments::mojom::blink::PaymentDelegation::PAYER_NAME);
+    } else if (delegation == "payerPhone") {
+      delegations.emplace_back(
+          payments::mojom::blink::PaymentDelegation::PAYER_PHONE);
+    } else {
+      DCHECK_EQ("payerEmail", delegation);
+      delegations.emplace_back(
+          payments::mojom::blink::PaymentDelegation::PAYER_EMAIL);
+    }
+  }
+
+  manager_->EnableDelegations(
+      std::move(delegations),
+      WTF::Bind(&PaymentManager::OnEnableDelegationsResponse,
+                WrapPersistent(this)));
+  enable_delegations_resolver_ =
+      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  return enable_delegations_resolver_->Promise();
+}
+
 void PaymentManager::Trace(blink::Visitor* visitor) {
   visitor->Trace(registration_);
   visitor->Trace(instruments_);
+  visitor->Trace(enable_delegations_resolver_);
   ScriptWrappable::Trace(visitor);
 }
 
@@ -57,7 +104,18 @@
                  registration_->scope());
 }
 
+void PaymentManager::OnEnableDelegationsResponse(
+    payments::mojom::blink::PaymentHandlerStatus status) {
+  DCHECK(enable_delegations_resolver_);
+  enable_delegations_resolver_->Resolve(
+      status == payments::mojom::blink::PaymentHandlerStatus::SUCCESS);
+  enable_delegations_resolver_.Clear();
+}
+
 void PaymentManager::OnServiceConnectionError() {
+  if (enable_delegations_resolver_)
+    enable_delegations_resolver_.Clear();
+
   manager_.reset();
 }
 
diff --git a/third_party/blink/renderer/modules/payments/payment_manager.h b/third_party/blink/renderer/modules/payments/payment_manager.h
index edd7cc80..d60f8bcc 100644
--- a/third_party/blink/renderer/modules/payments/payment_manager.h
+++ b/third_party/blink/renderer/modules/payments/payment_manager.h
@@ -8,7 +8,6 @@
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/payments/payment_app.mojom-blink.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
@@ -16,6 +15,9 @@
 namespace blink {
 
 class PaymentInstruments;
+class ScriptPromiseResolver;
+class ScriptPromise;
+class ScriptState;
 class ServiceWorkerRegistration;
 
 class MODULES_EXPORT PaymentManager final : public ScriptWrappable {
@@ -33,13 +35,21 @@
 
   void Trace(blink::Visitor*) override;
 
+  ScriptPromise enableDelegations(
+      ScriptState*,
+      const Vector<String>& stringified_delegations);
+
  private:
   void OnServiceConnectionError();
 
+  void OnEnableDelegationsResponse(
+      payments::mojom::blink::PaymentHandlerStatus status);
+
   Member<ServiceWorkerRegistration> registration_;
   mojo::Remote<payments::mojom::blink::PaymentManager> manager_;
   Member<PaymentInstruments> instruments_;
   String user_hint_;
+  Member<ScriptPromiseResolver> enable_delegations_resolver_;
 
   DISALLOW_COPY_AND_ASSIGN(PaymentManager);
 };
diff --git a/third_party/blink/renderer/modules/payments/payment_manager.idl b/third_party/blink/renderer/modules/payments/payment_manager.idl
index e213feb..10b88279 100644
--- a/third_party/blink/renderer/modules/payments/payment_manager.idl
+++ b/third_party/blink/renderer/modules/payments/payment_manager.idl
@@ -4,10 +4,18 @@
 
 // https://w3c.github.io/webpayments-payment-apps-api/#idl-def-paymentappmanager
 
+enum PaymentDelegation {
+    "shippingAddress",
+    "payerName",
+    "payerPhone",
+    "payerEmail",
+};
+
 [
     RuntimeEnabled=PaymentApp,
     ConstructorCallWith=ExecutionContext
 ] interface PaymentManager {
     [SameObject] readonly attribute PaymentInstruments instruments;
     attribute DOMString userHint;
+    [CallWith=ScriptState, RuntimeEnabled=PaymentHandlerHandlesShippingAndContact] Promise<void> enableDelegations(FrozenArray<PaymentDelegation> delegations);
 };
diff --git a/third_party/blink/renderer/modules/peerconnection/BUILD.gn b/third_party/blink/renderer/modules/peerconnection/BUILD.gn
index 98cef04..57d4956 100644
--- a/third_party/blink/renderer/modules/peerconnection/BUILD.gn
+++ b/third_party/blink/renderer/modules/peerconnection/BUILD.gn
@@ -126,6 +126,7 @@
 
   public_deps = [
     "//third_party/webrtc/api:ice_transport_factory",
+    "//third_party/webrtc/api:rtc_error",
     "//third_party/webrtc/api:scoped_refptr",
   ]
 }
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
index 1ace8be..4e34330 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
+++ b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
@@ -681,6 +681,21 @@
   return DAWN_TEXTURE_ASPECT_FORCE32;
 }
 
+template <>
+DawnErrorFilter AsDawnEnum<DawnErrorFilter>(const WTF::String& webgpu_enum) {
+  if (webgpu_enum == "none") {
+    return DAWN_ERROR_FILTER_NONE;
+  }
+  if (webgpu_enum == "out-of-memory") {
+    return DAWN_ERROR_FILTER_OUT_OF_MEMORY;
+  }
+  if (webgpu_enum == "validation") {
+    return DAWN_ERROR_FILTER_VALIDATION;
+  }
+  NOTREACHED();
+  return DAWN_ERROR_FILTER_FORCE32;
+}
+
 DawnColor AsDawnType(const GPUColor* webgpu_color) {
   DCHECK(webgpu_color);
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.cc b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
index 095392110..7d6a0eb 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
@@ -7,8 +7,10 @@
 #include "gpu/command_buffer/client/webgpu_interface.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
+#include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_adapter.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_bind_group.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.h"
@@ -209,6 +211,60 @@
   return queue_;
 }
 
+void GPUDevice::pushErrorScope(const WTF::String& filter) {
+  GetProcs().devicePushErrorScope(GetHandle(),
+                                  AsDawnEnum<DawnErrorFilter>(filter));
+}
+
+ScriptPromise GPUDevice::popErrorScope(ScriptState* script_state,
+                                       ExceptionState& exception_state) {
+  ScriptPromiseResolver* resolver =
+      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  ScriptPromise promise = resolver->Promise();
+
+  auto* callback =
+      BindDawnCallback(&GPUDevice::OnPopErrorScopeCallback,
+                       WrapPersistent(this), WrapPersistent(resolver));
+
+  if (!GetProcs().devicePopErrorScope(GetHandle(), callback->UnboundCallback(),
+                                      callback->AsUserdata())) {
+    exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+                                      "No error scopes to pop.");
+    delete callback;
+  }
+
+  // WebGPU guarantees callbacks complete in finite time. Flush now so that
+  // commands reach the GPU process. TODO(enga): This should happen at the end
+  // of the task.
+  GetInterface()->FlushCommands();
+
+  return promise;
+}
+
+void GPUDevice::OnPopErrorScopeCallback(ScriptPromiseResolver* resolver,
+                                        DawnErrorType type,
+                                        const char* message) {
+  ScriptState* script_state = resolver->GetScriptState();
+  switch (type) {
+    case DAWN_ERROR_TYPE_NO_ERROR:
+      resolver->Resolve(ScriptValue::CreateNull(script_state));
+      break;
+    case DAWN_ERROR_TYPE_OUT_OF_MEMORY:
+      resolver->Resolve(GPUOutOfMemoryError::Create());
+      break;
+    case DAWN_ERROR_TYPE_VALIDATION:
+      resolver->Resolve(GPUValidationError::Create(message));
+      break;
+    case DAWN_ERROR_TYPE_UNKNOWN:
+    case DAWN_ERROR_TYPE_DEVICE_LOST:
+      resolver->Reject(
+          MakeGarbageCollected<DOMException>(DOMExceptionCode::kAbortError));
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
 ExecutionContext* GPUDevice::GetExecutionContext() const {
   return ContextClient::GetExecutionContext();
 }
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.h b/third_party/blink/renderer/modules/webgpu/gpu_device.h
index 93c160cf..436c03c 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.h
@@ -41,6 +41,7 @@
 class GPUShaderModuleDescriptor;
 class GPUTexture;
 class GPUTextureDescriptor;
+class ScriptPromiseResolver;
 class ScriptState;
 
 class GPUDevice final : public EventTargetWithInlineData,
@@ -98,6 +99,10 @@
 
   GPUQueue* getQueue();
 
+  void pushErrorScope(const WTF::String& filter);
+  ScriptPromise popErrorScope(ScriptState* script_state,
+                              ExceptionState& exception_state);
+
   DEFINE_ATTRIBUTE_EVENT_LISTENER(uncapturederror, kUncapturederror)
 
   // EventTarget overrides.
@@ -109,6 +114,10 @@
                          DawnErrorType errorType,
                          const char* message);
 
+  void OnPopErrorScopeCallback(ScriptPromiseResolver* resolver,
+                               DawnErrorType type,
+                               const char* message);
+
   Member<GPUAdapter> adapter_;
   Member<GPUQueue> queue_;
   std::unique_ptr<
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.idl b/third_party/blink/renderer/modules/webgpu/gpu_device.idl
index 637a79b..f5c58eb2 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.idl
@@ -27,8 +27,17 @@
     GPURenderBundleEncoder createRenderBundleEncoder(GPURenderBundleEncoderDescriptor descriptor);
     GPUQueue getQueue();
 
+    void pushErrorScope(GPUErrorFilter filter);
+    [CallWith=ScriptState, RaisesException] Promise<GPUError?> popErrorScope();
+
     attribute EventHandler onuncapturederror;
 };
 
+enum GPUErrorFilter {
+    "none",
+    "out-of-memory",
+    "validation"
+};
+
 typedef sequence<any> GPUMappedBuffer;  // [GPUBuffer, ArrayBuffer]
 typedef (GPUOutOfMemoryError or GPUValidationError) GPUError;
diff --git a/third_party/blink/renderer/platform/blob/blob_data_test.cc b/third_party/blink/renderer/platform/blob/blob_data_test.cc
index 205596b..ee7a6b4d2f 100644
--- a/third_party/blink/renderer/platform/blob/blob_data_test.cc
+++ b/third_party/blink/renderer/platform/blob/blob_data_test.cc
@@ -24,7 +24,6 @@
 namespace blink {
 
 using mojom::blink::Blob;
-using mojom::blink::BlobPtr;
 using mojom::blink::BlobRegistry;
 using mojom::blink::DataElement;
 using mojom::blink::DataElementBlob;
@@ -203,7 +202,8 @@
 
         base::RunLoop loop;
         String received_uuid;
-        mojom::blink::BlobPtr blob(std::move(actual->get_blob()->blob));
+        mojo::Remote<mojom::blink::Blob> blob(
+            std::move(actual->get_blob()->blob));
         blob->GetInternalUUID(base::BindOnce(
             [](base::Closure quit_closure, String* uuid_out,
                const String& uuid) {
diff --git a/third_party/blink/renderer/platform/blob/serialized_blob_mojom_traits.cc b/third_party/blink/renderer/platform/blob/serialized_blob_mojom_traits.cc
index c58bb4ca..043ce32 100644
--- a/third_party/blink/renderer/platform/blob/serialized_blob_mojom_traits.cc
+++ b/third_party/blink/renderer/platform/blob/serialized_blob_mojom_traits.cc
@@ -16,7 +16,7 @@
     return false;
   *out = blink::BlobDataHandle::Create(
       uuid, type, data.size(),
-      data.TakeBlob<blink::mojom::blink::BlobPtrInfo>());
+      data.TakeBlob<mojo::PendingRemote<blink::mojom::blink::Blob>>());
   return true;
 }
 
diff --git a/third_party/blink/renderer/platform/exported/web_blob_info.cc b/third_party/blink/renderer/platform/exported/web_blob_info.cc
index 79fee2d6..9496a7da 100644
--- a/third_party/blink/renderer/platform/exported/web_blob_info.cc
+++ b/third_party/blink/renderer/platform/exported/web_blob_info.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/public/platform/web_blob_info.h"
 
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom-blink.h"
 #include "third_party/blink/renderer/platform/blob/blob_data.h"
 
@@ -13,12 +14,13 @@
                          const WebString& type,
                          uint64_t size,
                          mojo::ScopedMessagePipeHandle handle)
-    : WebBlobInfo(BlobDataHandle::Create(
-          uuid,
-          type,
-          size,
-          mojom::blink::BlobPtrInfo(std::move(handle),
-                                    mojom::blink::Blob::Version_))) {}
+    : WebBlobInfo(
+          BlobDataHandle::Create(uuid,
+                                 type,
+                                 size,
+                                 mojo::PendingRemote<mojom::blink::Blob>(
+                                     std::move(handle),
+                                     mojom::blink::Blob::Version_))) {}
 
 WebBlobInfo::WebBlobInfo(const WebString& uuid,
                          const WebString& file_path,
@@ -27,15 +29,16 @@
                          double last_modified,
                          uint64_t size,
                          mojo::ScopedMessagePipeHandle handle)
-    : WebBlobInfo(BlobDataHandle::Create(
-                      uuid,
-                      type,
-                      size,
-                      mojom::blink::BlobPtrInfo(std::move(handle),
-                                                mojom::blink::Blob::Version_)),
-                  file_path,
-                  file_name,
-                  last_modified) {}
+    : WebBlobInfo(
+          BlobDataHandle::Create(uuid,
+                                 type,
+                                 size,
+                                 mojo::PendingRemote<mojom::blink::Blob>(
+                                     std::move(handle),
+                                     mojom::blink::Blob::Version_)),
+          file_path,
+          file_name,
+          last_modified) {}
 
 // static
 WebBlobInfo WebBlobInfo::BlobForTesting(const WebString& uuid,
diff --git a/third_party/blink/renderer/platform/exported/web_http_body.cc b/third_party/blink/renderer/platform/exported/web_http_body.cc
index bc55a911..21a7552 100644
--- a/third_party/blink/renderer/platform/exported/web_http_body.cc
+++ b/third_party/blink/renderer/platform/exported/web_http_body.cc
@@ -143,11 +143,11 @@
                              uint64_t length,
                              mojo::ScopedMessagePipeHandle blob_handle) {
   EnsureMutable();
-  mojom::blink::BlobPtrInfo blob_ptr_info(std::move(blob_handle),
-                                          mojom::blink::Blob::Version_);
+  mojo::PendingRemote<mojom::blink::Blob> blob_remote(
+      std::move(blob_handle), mojom::blink::Blob::Version_);
   private_->AppendBlob(
       uuid, BlobDataHandle::Create(uuid, "" /* type is not necessary */, length,
-                                   std::move(blob_ptr_info)));
+                                   std::move(blob_remote)));
 }
 
 void WebHTTPBody::AppendDataPipe(mojo::ScopedMessagePipeHandle message_pipe) {
diff --git a/third_party/blink/renderer/platform/exported/web_mixed_content.cc b/third_party/blink/renderer/platform/exported/web_mixed_content.cc
index 858cad7..6b8f43b 100644
--- a/third_party/blink/renderer/platform/exported/web_mixed_content.cc
+++ b/third_party/blink/renderer/platform/exported/web_mixed_content.cc
@@ -30,6 +30,8 @@
 
 #include "third_party/blink/public/platform/web_mixed_content.h"
 
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
+
 namespace blink {
 
 // static
diff --git a/third_party/blink/renderer/platform/exported/web_url_request.cc b/third_party/blink/renderer/platform/exported/web_url_request.cc
index 8e67cec0..77327f7d 100644
--- a/third_party/blink/renderer/platform/exported/web_url_request.cc
+++ b/third_party/blink/renderer/platform/exported/web_url_request.cc
@@ -49,6 +49,8 @@
 
 namespace blink {
 
+WebURLRequest::ExtraData::ExtraData() : render_frame_id_(MSG_ROUTING_NONE) {}
+
 // The purpose of this struct is to permit allocating a ResourceRequest on the
 // heap, which is otherwise disallowed by DISALLOW_NEW annotation on
 // ResourceRequest.
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index 3256ca40..82a9ba30 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -1204,7 +1204,8 @@
         const bool is_accelerated =
             usage == ResourceUsage::kAcceleratedResourceUsage ||
             usage == ResourceUsage::kAcceleratedCompositedResourceUsage ||
-            usage == ResourceUsage::kAcceleratedDirect2DResourceUsage;
+            usage == ResourceUsage::kAcceleratedDirect2DResourceUsage ||
+            usage == ResourceUsage::kAcceleratedDirect3DResourceUsage;
 
         // If the rendering will be in software and we don't have GMB support,
         // fallback to bitmap provider type.
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
index 091c951..b14852c 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
@@ -482,4 +482,43 @@
   EXPECT_EQ(provider->NewOrRecycledResource(), resource);
 }
 
+// Verifies that Accelerated Direct 3D resources are backed by SharedImages.
+// https://crbug.com/985366
+TEST_F(CanvasResourceProviderTest, CanvasResourceProviderDirect3D) {
+  const IntSize kSize(10, 10);
+  const CanvasColorParams kColorParams(kSRGBCanvasColorSpace,
+                                       kRGBA8CanvasPixelFormat, kNonOpaque);
+
+  auto provider = CanvasResourceProvider::Create(
+      kSize,
+      CanvasResourceProvider::ResourceUsage::kAcceleratedDirect3DResourceUsage,
+      context_provider_wrapper_, 0 /* msaa_sample_count */,
+      kLow_SkFilterQuality, kColorParams,
+      CanvasResourceProvider::kDefaultPresentationMode,
+      nullptr /* resource_dispatcher */, true /* is_origin_top_left */);
+
+  EXPECT_EQ(provider->Size(), kSize);
+  EXPECT_TRUE(provider->IsValid());
+  EXPECT_TRUE(provider->IsAccelerated());
+  EXPECT_TRUE(provider->SupportsDirectCompositing());
+  EXPECT_FALSE(provider->SupportsSingleBuffering());
+  EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
+  EXPECT_EQ(provider->ColorParams().PixelFormat(), kColorParams.PixelFormat());
+  EXPECT_EQ(provider->ColorParams().GetOpacityMode(),
+            kColorParams.GetOpacityMode());
+
+  EXPECT_FALSE(provider->IsSingleBuffered());
+  provider->TryEnableSingleBuffering();
+  EXPECT_FALSE(provider->IsSingleBuffered());
+
+  auto resource = provider->ProduceCanvasResource();
+  viz::TransferableResource transferable_resource;
+  std::unique_ptr<viz::SingleReleaseCallback> callback;
+  resource->PrepareTransferableResource(&transferable_resource, &callback,
+                                        kOrderingBarrier);
+  EXPECT_TRUE(transferable_resource.mailbox_holder.mailbox.IsSharedImage());
+  EXPECT_FALSE(transferable_resource.is_overlay_candidate);
+  callback->Run(gpu::SyncToken(), true /* is_lost */);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.cc b/third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.cc
index 7de8d472..f3bfe431 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.cc
@@ -58,6 +58,10 @@
   context_attributes.enable_raster_interface = true;
   context_attributes.support_grcontext = true;
 
+  // The shared GPU context should not trigger a switch to the high-performance
+  // GPU.
+  context_attributes.prefer_low_power_gpu = true;
+
   *gpu_compositing_disabled = Platform::Current()->IsGpuCompositingDisabled();
   if (*gpu_compositing_disabled && only_if_gpu_compositing) {
     waitable_event->Signal();
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_request.cc b/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
index 952e86f..dd03984f 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
@@ -29,6 +29,7 @@
 #include <memory>
 
 #include "base/unguessable_token.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/platform/network/encoded_form_data.h"
 #include "third_party/blink/renderer/platform/network/http_names.h"
diff --git a/third_party/blink/renderer/platform/network/encoded_form_data_element_mojom_traits.cc b/third_party/blink/renderer/platform/network/encoded_form_data_element_mojom_traits.cc
index 2d1cbc5..0df4fbe 100644
--- a/third_party/blink/renderer/platform/network/encoded_form_data_element_mojom_traits.cc
+++ b/third_party/blink/renderer/platform/network/encoded_form_data_element_mojom_traits.cc
@@ -11,6 +11,7 @@
 #include "mojo/public/cpp/base/file_path_mojom_traits.h"
 #include "mojo/public/cpp/base/time_mojom_traits.h"
 #include "mojo/public/cpp/bindings/array_traits_wtf_vector.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/bindings/string_traits_wtf.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/data_pipe_getter.mojom-blink.h"
@@ -80,12 +81,13 @@
   }
   if (data.type_ == blink::FormDataElement::kEncodedBlob) {
     if (data.optional_blob_data_handle_) {
-      blink::mojom::blink::BlobPtr blob_ptr(blink::mojom::blink::BlobPtrInfo(
-          data.optional_blob_data_handle_->CloneBlobRemote().PassPipe(),
-          blink::mojom::blink::Blob::Version_));
+      mojo::Remote<blink::mojom::blink::Blob> blob_remote(
+          mojo::PendingRemote<blink::mojom::blink::Blob>(
+              data.optional_blob_data_handle_->CloneBlobRemote().PassPipe(),
+              blink::mojom::blink::Blob::Version_));
       mojo::PendingRemote<network::mojom::blink::DataPipeGetter>
           data_pipe_getter_remote;
-      blob_ptr->AsDataPipeGetter(
+      blob_remote->AsDataPipeGetter(
           data_pipe_getter_remote.InitWithNewPipeAndPassReceiver());
       return data_pipe_getter_remote;
     }
diff --git a/third_party/blink/renderer/platform/network/encoded_form_data_test.cc b/third_party/blink/renderer/platform/network/encoded_form_data_test.cc
index 13d1d769..461380f 100644
--- a/third_party/blink/renderer/platform/network/encoded_form_data_test.cc
+++ b/third_party/blink/renderer/platform/network/encoded_form_data_test.cc
@@ -148,7 +148,7 @@
   mojo::MessagePipe pipe;
   original3.optional_blob_data_handle_ = BlobDataHandle::Create(
       original3.blob_uuid_, "type-test", 100,
-      mojom::blink::BlobPtrInfo(std::move(pipe.handle0), 0));
+      mojo::PendingRemote<mojom::blink::Blob>(std::move(pipe.handle0), 0));
   FormDataElement copied3;
   EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
               blink::mojom::blink::FetchAPIDataElement>(&original3, &copied3));
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index e4dd811..19103194 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1218,6 +1218,10 @@
       status: "stable",
     },
     {
+      name: "PaymentHandlerHandlesShippingAndContact",
+      status: "experimental",
+    },
+    {
       name: "PaymentMethodChangeEvent",
       status: "stable",
     },
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 8586359..c62d132 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
@@ -13783,6 +13783,18 @@
      {}
     ]
    ],
+   "css/CSS2/linebox/vertical-align-negative-leading-001.html": [
+    [
+     "css/CSS2/linebox/vertical-align-negative-leading-001.html",
+     [
+      [
+       "/css/CSS2/linebox/vertical-align-negative-leading-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/CSS2/linebox/vertical-align-nested-top-001.html": [
     [
      "css/CSS2/linebox/vertical-align-nested-top-001.html",
@@ -130660,6 +130672,9 @@
    "css/CSS2/linebox/vertical-align-baseline-008-ref.xht": [
     []
    ],
+   "css/CSS2/linebox/vertical-align-negative-leading-001-ref.html": [
+    []
+   ],
    "css/CSS2/linebox/vertical-align-nested-top-001-ref.html": [
     []
    ],
@@ -132868,9 +132883,6 @@
    "css/css-backgrounds/parsing/background-position-y-valid-expected.txt": [
     []
    ],
-   "css/css-backgrounds/parsing/border-radius-valid-expected.txt": [
-    []
-   ],
    "css/css-backgrounds/reference/60x60-green-background.html": [
     []
    ],
@@ -143281,6 +143293,9 @@
    "css/css-text-decor/inheritance-expected.txt": [
     []
    ],
+   "css/css-text-decor/parsing/text-decoration-computed-expected.txt": [
+    []
+   ],
    "css/css-text-decor/parsing/text-decoration-line-computed-expected.txt": [
     []
    ],
@@ -147937,9 +147952,6 @@
    "css/css-variables/variable-invalidation-expected.txt": [
     []
    ],
-   "css/css-variables/variable-presentation-attribute-expected.txt": [
-    []
-   ],
    "css/css-variables/variable-reference-visited-ref.html": [
     []
    ],
@@ -204831,6 +204843,12 @@
      {}
     ]
    ],
+   "css/css-backgrounds/parsing/border-radius-computed.html": [
+    [
+     "css/css-backgrounds/parsing/border-radius-computed.html",
+     {}
+    ]
+   ],
    "css/css-backgrounds/parsing/border-radius-invalid.html": [
     [
      "css/css-backgrounds/parsing/border-radius-invalid.html",
@@ -340943,6 +340961,14 @@
    "3534f496514ec6bc68f7877f63b8ebab5c9c6e29",
    "visual"
   ],
+  "css/CSS2/linebox/vertical-align-negative-leading-001-ref.html": [
+   "2f46ad1d8c96c6d713a458c28cd5c0bb54165cd0",
+   "support"
+  ],
+  "css/CSS2/linebox/vertical-align-negative-leading-001.html": [
+   "328e652cd270f1c5b1c13e47b8f499e7358a28c6",
+   "reftest"
+  ],
   "css/CSS2/linebox/vertical-align-nested-top-001-ref.html": [
    "1fd155e38013e555c140908310c36b1416ac2ded",
    "support"
@@ -346588,7 +346614,7 @@
    "visual"
   ],
   "css/CSS2/positioning/inline-static-position-001.html": [
-   "d5695bd75246f9482ee6250213c38a7311919ec5",
+   "b627fbcab58d0a988de8ef572f64a67c2929536b",
    "testharness"
   ],
   "css/CSS2/positioning/left-004-ref.xht": [
@@ -352272,7 +352298,7 @@
    "testharness"
   ],
   "css/css-backgrounds/animations/background-position-interpolation.html": [
-   "35100fb33622c03f6454ebc051569ccba67564e9",
+   "2e7f2e24a1db1c6dd34033a753327e0ed3b08276",
    "testharness"
   ],
   "css/css-backgrounds/animations/background-position-origin-interpolation.html": [
@@ -355335,16 +355361,16 @@
    "71404f2ce3e18fe336f076ce72ad028c4f665861",
    "testharness"
   ],
-  "css/css-backgrounds/parsing/border-radius-invalid.html": [
-   "4e004af8f36beb4651a8069e38f246136bb35451",
+  "css/css-backgrounds/parsing/border-radius-computed.html": [
+   "9799be68ec73a36c3e956a9c1f3931e838e684ed",
    "testharness"
   ],
-  "css/css-backgrounds/parsing/border-radius-valid-expected.txt": [
-   "b0af22e9bcfa107487c8edf371582a6a3fc6424d",
-   "support"
+  "css/css-backgrounds/parsing/border-radius-invalid.html": [
+   "f6d1bcb081e233eaab41c39290a0d16813800274",
+   "testharness"
   ],
   "css/css-backgrounds/parsing/border-radius-valid.html": [
-   "317803bf8819b2147390434e78d4efdcdc6d906b",
+   "738362f96933c34fae38e6adfa9a82a556fc1f3b",
    "testharness"
   ],
   "css/css-backgrounds/parsing/border-style-computed.html": [
@@ -385103,8 +385129,12 @@
    "f1998f045a4bb775c464a50578683b20a66d5baa",
    "testharness"
   ],
+  "css/css-text-decor/parsing/text-decoration-computed-expected.txt": [
+   "6f128b0126e2c4479f19d89868cf161108beaae9",
+   "support"
+  ],
   "css/css-text-decor/parsing/text-decoration-computed.html": [
-   "75a6f6b601adbc979c2ba8da8b44fd4afc372462",
+   "af577b17416596d630e982b47dfca42ad5669893",
    "testharness"
   ],
   "css/css-text-decor/parsing/text-decoration-invalid.html": [
@@ -385688,11 +385718,11 @@
    "reftest"
   ],
   "css/css-text-decor/text-decoration-serialization.tentative-expected.txt": [
-   "2fac902c4641be1db62dc791301731042c21d1c6",
+   "0d83f58028ff740b492af6663ff5b135a740b9a1",
    "support"
   ],
   "css/css-text-decor/text-decoration-serialization.tentative.html": [
-   "2f7b2f55fea63bbb2c752c4c79e4e3415f1578be",
+   "73cb5cc5cea7c6f63609bcf32f34e9096e479a2f",
    "testharness"
   ],
   "css/css-text-decor/text-decoration-shorthands-001.html": [
@@ -404727,12 +404757,8 @@
    "677f217c88036ecda57b1ff62648463ecce564fe",
    "testharness"
   ],
-  "css/css-variables/variable-presentation-attribute-expected.txt": [
-   "6cfb57ddf82b3cad24ff6d0579de03b11907bb23",
-   "support"
-  ],
   "css/css-variables/variable-presentation-attribute.html": [
-   "924c8e1c053afd4ae8949d13b03a0e6921369883",
+   "6c8a4430bc7bcffcb6b85c018cc92c0d25320fe6",
    "testharness"
   ],
   "css/css-variables/variable-pseudo-element.html": [
@@ -480448,7 +480474,7 @@
    "support"
   ],
   "resources/chromium/webxr-test.js": [
-   "73dda0920f12fb0f674f41765b27bd1c3c4a6b6a",
+   "894e2a24f653e150b738fc576135ed4871a3a644",
    "support"
   ],
   "resources/chromium/webxr-test.js.headers": [
@@ -493720,7 +493746,7 @@
    "support"
   ],
   "tools/webdriver/webdriver/client.py": [
-   "5425572016076494cd1d7da6576a6c7a53c9015e",
+   "0bddd7b13738321ed57c6df1ed6f316b3a5c7eb5",
    "support"
   ],
   "tools/webdriver/webdriver/error.py": [
@@ -497028,7 +497054,7 @@
    "support"
   ],
   "web-share/share-cancel-manual.html": [
-   "b523fb5c221ec71e64ba74f3c9ac23f03d8e5760",
+   "b078a74251cff1f566107f14e39a3b926f74f16c",
    "manual"
   ],
   "web-share/share-empty.https.html": [
@@ -497036,11 +497062,11 @@
    "testharness"
   ],
   "web-share/share-extra-argument-manual.html": [
-   "29e7a5645440f5978f56491c1c2e4b730c89ba97",
+   "47ef7fa1158578e3b6bf51ac12fd3f486e52b054",
    "manual"
   ],
   "web-share/share-extra-field-manual.html": [
-   "d601c7df7ab7896c775d26fb1a2488fa8f827dc7",
+   "8b479bb02b9c91b82a7e71272fc26735a4ca1ca5",
    "manual"
   ],
   "web-share/share-files-manual.html": [
@@ -497112,7 +497138,7 @@
    "manual"
   ],
   "web-share/share-without-user-gesture.https.html": [
-   "cf933b8bc7fcac181ead4c2e1059539525e84197",
+   "48e03b0fc3b2db8f3c96231f49096e2eb7b92064",
    "testharness"
   ],
   "webaudio/.gitignore": [
@@ -505504,11 +505530,11 @@
    "testharness"
   ],
   "webxr/xrReferenceSpace_originOffset.https.html": [
-   "fd5fa68e1fc4a837b8bef41876a36278e6bb84fb",
+   "e7fe576cb2013647c18111c7fc2d74afdd7ee04d",
    "testharness"
   ],
   "webxr/xrReferenceSpace_originOffsetBounded.https.html": [
-   "5e2bd39d2dee2d6c2146b7a421371db0360c0577",
+   "cfa3cc7ca2fe7cfbd656d9164b0d1ab3dd60ca41",
    "testharness"
   ],
   "webxr/xrRigidTransform_constructor.https.html": [
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/linebox/vertical-align-negative-leading-001-ref.html b/third_party/blink/web_tests/external/wpt/css/CSS2/linebox/vertical-align-negative-leading-001-ref.html
new file mode 100644
index 0000000..2f46ad1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/linebox/vertical-align-negative-leading-001-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<style>
+.container {
+  margin: 30px 0;
+  color: orange;
+  background-color: blue;
+  line-height: 10px;
+  font-size: 30px;
+  font-family: Ahem;
+}
+.lh20 { line-height: 20px; }
+.lh30 { line-height: 30px; }
+.up5 { position: relative; top: -5px; }
+.up10 { position: relative; top: -10px; }
+.down5 { position: relative; top: 5px; }
+.down10 { position: relative; top: 10px; }
+</style>
+<body>
+<div class="container">
+  <span>XX</span>
+  <span>XX</span>
+  <span>XX</span>
+</div>
+<div class="container lh30">
+  <span class="up10">XX</span>
+  <span>XX</span>
+  <span class="down10">XX</span>
+</div>
+<div class="container"><span>XX</span></div>
+<div class="container"><span>XX</span></div>
+<div class="container lh20"><span class="up5">XX</span></div>
+<div class="container lh20"><span class="down5">XX</span></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/linebox/vertical-align-negative-leading-001.html b/third_party/blink/web_tests/external/wpt/css/CSS2/linebox/vertical-align-negative-leading-001.html
new file mode 100644
index 0000000..328e652
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/linebox/vertical-align-negative-leading-001.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>Test vertical-align: top and bottom do not affect the line height</title>
+<link rel="match" href="vertical-align-negative-leading-001-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#propdef-vertical-align">
+<link rel="author" href="mailto:kojii@chromium.org">
+<style>
+.container {
+  margin: 30px 0;
+  color: orange;
+  background-color: blue;
+  line-height: 10px;
+  font-size: 30px;
+  font-family: Ahem;
+}
+span { background: purple; }
+.top { vertical-align: top; }
+.bottom { vertical-align: bottom; }
+.text-top { vertical-align: text-top; }
+.text-bottom { vertical-align: text-bottom; }
+</style>
+<body>
+<div class="container">
+  <span class="top">XX</span>
+  <span>XX</span>
+  <span class="bottom">XX</span>
+</div>
+<div class="container">
+  <span class="text-top">XX</span>
+  <span>XX</span>
+  <span class="text-bottom">XX</span>
+</div>
+<div class="container"><span class="top">XX</span></div>
+<div class="container"><span class="bottom">XX</span></div>
+<div class="container"><span class="text-top">XX</span></div>
+<div class="container"><span class="text-bottom">XX</span></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/positioning/inline-static-position-001.html b/third_party/blink/web_tests/external/wpt/css/CSS2/positioning/inline-static-position-001.html
index d5695bd..b627fbca 100644
--- a/third_party/blink/web_tests/external/wpt/css/CSS2/positioning/inline-static-position-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/positioning/inline-static-position-001.html
@@ -5,6 +5,7 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/check-layout-th.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 .tests, .no-tests {
   margin-bottom: 1em;
@@ -42,6 +43,8 @@
     <div>123456789012&nbsp;<span class="abs">span</span>&nbsp;543210987654321</div>
   </section>
 <script>
-checkLayout('.tests .abs');
+document.fonts.ready.then(()=> {
+  checkLayout('.tests .abs');
+});
 </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-computed-expected.txt
new file mode 100644
index 0000000..6f128b0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-computed-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+FAIL Property text-decoration value 'none' computes to 'rgb(0, 0, 255)' assert_equals: expected "rgb(0, 0, 255)" but got "none solid rgb(0, 0, 255)"
+FAIL Property text-decoration value 'line-through' computes to 'line-through rgb(0, 0, 255)' assert_equals: expected "line-through rgb(0, 0, 255)" but got "line-through solid rgb(0, 0, 255)"
+FAIL Property text-decoration value 'solid' computes to 'rgb(0, 0, 255)' assert_equals: expected "rgb(0, 0, 255)" but got "none solid rgb(0, 0, 255)"
+FAIL Property text-decoration value 'currentcolor' computes to 'rgb(0, 0, 255)' assert_equals: expected "rgb(0, 0, 255)" but got "none solid rgb(0, 0, 255)"
+PASS Property text-decoration value 'double overline underline' computes to 'underline overline double rgb(0, 0, 255)'
+FAIL Property text-decoration value 'underline overline line-through red' computes to 'underline overline line-through rgb(255, 0, 0)' assert_equals: expected "underline overline line-through rgb(255, 0, 0)" but got "underline overline line-through solid rgb(255, 0, 0)"
+FAIL Property text-decoration value 'rgba(10, 20, 30, 0.4) dotted' computes to 'dotted rgba(10, 20, 30, 0.4)' assert_equals: expected "dotted rgba(10, 20, 30, 0.4)" but got "none dotted rgba(10, 20, 30, 0.4)"
+PASS Property text-decoration value 'underline dashed rgb(0, 255, 0)' computes to 'underline dashed rgb(0, 255, 0)'
+FAIL Property text-decoration value 'auto' computes to 'rgb(0, 0, 255)' assert_equals: expected "rgb(0, 0, 255)" but got "none solid rgb(0, 0, 255)"
+FAIL Property text-decoration value 'from-font' computes to 'rgb(0, 0, 255) from-font' assert_equals: expected "rgb(0, 0, 255) from-font" but got "none solid rgb(0, 0, 255)"
+FAIL Property text-decoration value '10px' computes to 'rgb(0, 0, 255) 10px' assert_equals: expected "rgb(0, 0, 255) 10px" but got "none solid rgb(0, 0, 255)"
+FAIL Property text-decoration value 'underline red from-font' computes to 'underline rgb(255, 0, 0) from-font' assert_equals: expected "underline rgb(255, 0, 0) from-font" but got "none solid rgb(0, 0, 255)"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-computed.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-computed.html
index 75a6f6b..af577b1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-computed.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-computed.html
@@ -3,7 +3,7 @@
 <head>
 <meta charset="utf-8">
 <title>CSS Text Decoration Test: getComputedStyle().textDecoration</title>
-<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-line-property">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-decoration-property">
 <meta name="assert" content="text-decoration computed value is as specified.">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
@@ -19,14 +19,20 @@
 <script>
 'use strict';
 const currentColor = "rgb(0, 0, 255)";
-test_computed_value("text-decoration", "none", "none solid " + currentColor);
-test_computed_value("text-decoration", "line-through", "line-through solid " + currentColor);
-test_computed_value("text-decoration", "solid", "none solid " + currentColor);
-test_computed_value("text-decoration", "currentcolor", "none solid " + currentColor);
+test_computed_value("text-decoration", "none", currentColor);
+test_computed_value("text-decoration", "line-through", "line-through " + currentColor);
+test_computed_value("text-decoration", "solid", currentColor);
+test_computed_value("text-decoration", "currentcolor", currentColor);
 
 test_computed_value("text-decoration", "double overline underline", "underline overline double " + currentColor);
-test_computed_value("text-decoration", "underline overline line-through red", "underline overline line-through solid rgb(255, 0, 0)");
-test_computed_value("text-decoration", "rgba(10, 20, 30, 0.4) dotted", "none dotted rgba(10, 20, 30, 0.4)");
+test_computed_value("text-decoration", "underline overline line-through red", "underline overline line-through rgb(255, 0, 0)");
+test_computed_value("text-decoration", "rgba(10, 20, 30, 0.4) dotted", "dotted rgba(10, 20, 30, 0.4)");
 
 test_computed_value("text-decoration", "underline dashed rgb(0, 255, 0)");
+
+// Add text-decoration-thickness in [css-text-decor-4].
+test_computed_value("text-decoration", "auto", currentColor);
+test_computed_value("text-decoration", "from-font", currentColor + " from-font");
+test_computed_value("text-decoration", "10px", currentColor + " 10px");
+test_computed_value("text-decoration", "underline red from-font", "underline rgb(255, 0, 0) from-font");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-serialization.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-serialization.tentative-expected.txt
index 2fac902..0d83f580 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-serialization.tentative-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-serialization.tentative-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL text-decoration shorthand serialization assert_equals: expected "underline" but got "underline solid rgb(0, 0, 0)"
+FAIL text-decoration shorthand serialization assert_equals: expected "underline rgb(0, 0, 0)" but got "underline solid rgb(0, 0, 0)"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-serialization.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-serialization.tentative.html
index 2f7b2f55..73cb5cc 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-serialization.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-serialization.tentative.html
@@ -8,10 +8,11 @@
 <script>
 test(() => {
   const style = getComputedStyle(document.querySelector('div'));
-  // Chrome serializes as "underline solid rgb(0, 0, 0)" while Edge, Firefox an
-  // Safari use "underline", which Chrome used to do as well. The spec should
-  // probably require "underline":
-  // https://github.com/w3c/csswg-drafts/issues/1564
-  assert_equals(style.getPropertyValue("text-decoration"), "underline");
+  const currentColor = "rgb(0, 0, 0)"; // The default color value is black.
+  // The default computed value of text-decoration-color is depended on the
+  // current color value, and it is an rgb() value, instead of `currentcolor`.
+  // This is an ambiguous part in the spec, anyway.
+  assert_equals(style.getPropertyValue("text-decoration"),
+                "underline " + currentColor);
 });
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-variables/variable-presentation-attribute.html b/third_party/blink/web_tests/external/wpt/css/css-variables/variable-presentation-attribute.html
index 924c8e1..6c8a443 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-variables/variable-presentation-attribute.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-variables/variable-presentation-attribute.html
@@ -91,7 +91,8 @@
             { property: "stroke-opacity", valuesToTest:["0.221"], default: "1" },
             { property: "stroke-width", valuesToTest:["88%", "31px"], default: "1px" },
             { property: "text-anchor", valuesToTest:["start", "middle", "end"], default: "start" },
-            { property: "text-decoration", valuesToTest:["none", "underline", "overline", "line-through"], default: "none" },
+            { property: "text-decoration-line", valuesToTest:["none", "underline", "overline", "line-through"], default: "none" },
+            { property: "text-decoration-style", valuesToTest:["solid", "double", "dotted", "dashed", "wavy"], default: "solid" },
             { property: "visibility", valuesToTest:["visible", "hidden", "collapse"], default: "visible" },
             { property: "word-spacing", valuesToTest:["31px"], default: "0px" },
             { property: "writing-mode", valuesToTest:["lr-tb", "rl-tb"], default: "lr-tb" },
diff --git a/third_party/blink/web_tests/external/wpt/tools/webdriver/webdriver/client.py b/third_party/blink/web_tests/external/wpt/tools/webdriver/webdriver/client.py
index 5425572..0bddd7b 100644
--- a/third_party/blink/web_tests/external/wpt/tools/webdriver/webdriver/client.py
+++ b/third_party/blink/web_tests/external/wpt/tools/webdriver/webdriver/client.py
@@ -114,17 +114,17 @@
         """Perform all queued actions."""
         self.session.actions.perform([self.dict])
 
-    def _key_action(self, subtype, value, async_dispatch=False):
-        self._actions.append({"type": subtype, "value": value, "asyncDispatch": async_dispatch})
+    def _key_action(self, subtype, value):
+        self._actions.append({"type": subtype, "value": value})
 
-    def _pointer_action(self, subtype, button, async_dispatch=False):
-        self._actions.append({"type": subtype, "button": button, "asyncDispatch": async_dispatch})
+    def _pointer_action(self, subtype, button):
+        self._actions.append({"type": subtype, "button": button})
 
     def pause(self, duration):
         self._actions.append({"type": "pause", "duration": duration})
         return self
 
-    def pointer_move(self, x, y, duration=None, origin=None, async_dispatch=False):
+    def pointer_move(self, x, y, duration=None, origin=None):
         """Queue a pointerMove action.
 
         :param x: Destination x-axis coordinate of pointer in CSS pixels.
@@ -143,29 +143,28 @@
             action["duration"] = duration
         if origin is not None:
             action["origin"] = origin
-        action["asyncDispatch"] = async_dispatch
         self._actions.append(action)
         return self
 
-    def pointer_up(self, button=0, async_dispatch=False):
+    def pointer_up(self, button=0):
         """Queue a pointerUp action for `button`.
 
         :param button: Pointer button to perform action with.
                        Default: 0, which represents main device button.
         """
-        self._pointer_action("pointerUp", button, async_dispatch)
+        self._pointer_action("pointerUp", button)
         return self
 
-    def pointer_down(self, button=0, async_dispatch=False):
+    def pointer_down(self, button=0):
         """Queue a pointerDown action for `button`.
 
         :param button: Pointer button to perform action with.
                        Default: 0, which represents main device button.
         """
-        self._pointer_action("pointerDown", button, async_dispatch)
+        self._pointer_action("pointerDown", button)
         return self
 
-    def click(self, element=None, button=0, async_dispatch=False):
+    def click(self, element=None, button=0):
         """Queue a click with the specified button.
 
         If an element is given, move the pointer to that element first,
@@ -176,33 +175,33 @@
                        with. Default: 0, which represents main device button.
         """
         if element:
-            self.pointer_move(0, 0, origin=element, async_dispatch=async_dispatch)
-        return self.pointer_down(button, async_dispatch).pointer_up(button, async_dispatch)
+            self.pointer_move(0, 0, origin=element)
+        return self.pointer_down(button).pointer_up(button)
 
-    def key_up(self, value, async_dispatch=False):
+    def key_up(self, value):
         """Queue a keyUp action for `value`.
 
         :param value: Character to perform key action with.
         """
-        self._key_action("keyUp", value, async_dispatch)
+        self._key_action("keyUp", value)
         return self
 
-    def key_down(self, value, async_dispatch=False):
+    def key_down(self, value):
         """Queue a keyDown action for `value`.
 
         :param value: Character to perform key action with.
         """
-        self._key_action("keyDown", value, async_dispatch)
+        self._key_action("keyDown", value)
         return self
 
-    def send_keys(self, keys, async_dispatch=False):
+    def send_keys(self, keys):
         """Queue a keyDown and keyUp action for each character in `keys`.
 
         :param keys: String of keys to perform key actions with.
         """
         for c in keys:
-            self.key_down(c, async_dispatch)
-            self.key_up(c, async_dispatch)
+            self.key_down(c)
+            self.key_up(c)
         return self
 
 
diff --git a/third_party/blink/web_tests/external/wpt/web-share/share-cancel-manual.html b/third_party/blink/web_tests/external/wpt/web-share/share-cancel-manual.html
index b523fb5..b078a74 100644
--- a/third_party/blink/web_tests/external/wpt/web-share/share-cancel-manual.html
+++ b/third_party/blink/web_tests/external/wpt/web-share/share-cancel-manual.html
@@ -17,7 +17,7 @@
           return callWhenButtonClicked(() => promise_rejects(
               t, 'AbortError',
               navigator.share({title: 'the title', text: 'the message',
-                               url: 'data:the url'})));
+                               url: 'https://example.com'})));
         }, 'share with user cancellation');
     </script>
   </body>
diff --git a/third_party/blink/web_tests/external/wpt/web-share/share-extra-argument-manual.html b/third_party/blink/web_tests/external/wpt/web-share/share-extra-argument-manual.html
index 29e7a564..47ef7fa 100644
--- a/third_party/blink/web_tests/external/wpt/web-share/share-extra-argument-manual.html
+++ b/third_party/blink/web_tests/external/wpt/web-share/share-extra-argument-manual.html
@@ -12,9 +12,9 @@
         setup({explicit_timeout: true});
 
         setupManualShareTest(
-            {title: 'the title', text: 'the message', url: 'data:the url'});
+            {title: 'the title', text: 'the message', url: 'https://example.com'});
         callWhenButtonClicked(() => navigator.share(
-              {title: 'the title', text: 'the message', url: 'data:the url'},
+              {title: 'the title', text: 'the message', url: 'https://example.com'},
               'more than required'));
     </script>
   </body>
diff --git a/third_party/blink/web_tests/external/wpt/web-share/share-extra-field-manual.html b/third_party/blink/web_tests/external/wpt/web-share/share-extra-field-manual.html
index d601c7df..8b479bb0 100644
--- a/third_party/blink/web_tests/external/wpt/web-share/share-extra-field-manual.html
+++ b/third_party/blink/web_tests/external/wpt/web-share/share-extra-field-manual.html
@@ -12,9 +12,9 @@
         setup({explicit_timeout: true});
 
         setupManualShareTest(
-            {title: 'the title', text: 'the message', url: 'data:the url'});
+            {title: 'the title', text: 'the message', url: 'https://example.com'});
         callWhenButtonClicked(() => navigator.share(
-              {title: 'the title', text: 'the message', url: 'data:the url',
+              {title: 'the title', text: 'the message', url: 'https://example.com',
                unused: 'unexpected field'}));
     </script>
   </body>
diff --git a/third_party/blink/web_tests/external/wpt/web-share/share-without-user-gesture.https.html b/third_party/blink/web_tests/external/wpt/web-share/share-without-user-gesture.https.html
index cf933b8..48e03b0 100644
--- a/third_party/blink/web_tests/external/wpt/web-share/share-without-user-gesture.https.html
+++ b/third_party/blink/web_tests/external/wpt/web-share/share-without-user-gesture.https.html
@@ -12,7 +12,7 @@
           return promise_rejects(
               t, 'NotAllowedError',
               navigator.share({title: 'the title', text: 'the message',
-                               url: 'data:the url'}));
+                               url: 'https://example.com'}));
         }, 'share without a user gesture');
     </script>
   </body>
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-variables/variable-presentation-attribute-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-variables/variable-presentation-attribute-expected.txt
index c1bfce1..b76b750 100644
--- a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-variables/variable-presentation-attribute-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-variables/variable-presentation-attribute-expected.txt
@@ -43,7 +43,8 @@
 PASS Testing 'stroke-opacity'.
 PASS Testing 'stroke-width'.
 PASS Testing 'text-anchor'.
-FAIL Testing 'text-decoration'. assert_equals: Default value. expected "none" but got "none solid rgb(0, 0, 0)"
+PASS Testing 'text-decoration-line'.
+PASS Testing 'text-decoration-style'.
 PASS Testing 'visibility'.
 PASS Testing 'word-spacing'.
 FAIL Testing 'writing-mode'. assert_equals: Default value. expected "lr-tb" but got "horizontal-tb"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-variables/variable-presentation-attribute-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/css/css-variables/variable-presentation-attribute-expected.txt
similarity index 95%
rename from third_party/blink/web_tests/external/wpt/css/css-variables/variable-presentation-attribute-expected.txt
rename to third_party/blink/web_tests/platform/win/external/wpt/css/css-variables/variable-presentation-attribute-expected.txt
index 6cfb57d..18fbbeda 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-variables/variable-presentation-attribute-expected.txt
+++ b/third_party/blink/web_tests/platform/win/external/wpt/css/css-variables/variable-presentation-attribute-expected.txt
@@ -43,7 +43,8 @@
 PASS Testing 'stroke-opacity'.
 PASS Testing 'stroke-width'.
 PASS Testing 'text-anchor'.
-FAIL Testing 'text-decoration'. assert_equals: Default value. expected "none" but got "none solid rgb(0, 0, 0)"
+PASS Testing 'text-decoration-line'.
+PASS Testing 'text-decoration-style'.
 PASS Testing 'visibility'.
 PASS Testing 'word-spacing'.
 FAIL Testing 'writing-mode'. assert_equals: Default value. expected "lr-tb" but got "horizontal-tb"
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 843f718c5..aec37ea5 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -5506,6 +5506,7 @@
     getter instruments
     getter userHint
     method constructor
+    method enableDelegations
     setter userHint
 interface PaymentMethodChangeEvent : PaymentRequestUpdateEvent
     attribute @@toStringTag
diff --git a/third_party/harfbuzz-ng/BUILD.gn b/third_party/harfbuzz-ng/BUILD.gn
index 88bc9cc..9544abf 100644
--- a/third_party/harfbuzz-ng/BUILD.gn
+++ b/third_party/harfbuzz-ng/BUILD.gn
@@ -106,6 +106,9 @@
       "src/src/hb-map.hh",
       "src/src/hb-meta.hh",
       "src/src/hb-mutex.hh",
+      "src/src/hb-number-parser.hh",
+      "src/src/hb-number.cc",
+      "src/src/hb-number.hh",
       "src/src/hb-object.hh",
       "src/src/hb-open-file.hh",
       "src/src/hb-open-type.hh",
@@ -230,6 +233,7 @@
       "HAVE_ICU",
       "HAVE_ICU_BUILTIN",
       "HAVE_INTEL_ATOMIC_PRIMITIVES",
+      "HAVE_ROUNDF",
       "HB_NO_MMAP",
 
       # Size reductions by disabling parts that we do not currently require:
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium
index e0a2d29b..58e6e57 100644
--- a/third_party/harfbuzz-ng/README.chromium
+++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,9 +1,9 @@
 Name: harfbuzz-ng
 Short Name: harfbuzz-ng
 URL: http://harfbuzz.org
-Version: 2.6.0-21
-Date: 20190820
-Revision: bbad1b8298125d78c159ed7fdd7bde6a3f3fff56
+Version: 2.6.1-94
+Date: 20190910
+Revision: 170b5dd856b1ba8f26e79863fe0c64a52eb68951
 Security Critical: yes
 License: MIT
 License File: src/COPYING
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index 2fb8c7a..61fea63 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -36,8 +36,31 @@
 
 import gn_helpers
 
+def PruneVirtualEnv():
+  # Set by VirtualEnv, no need to keep it.
+  os.environ.pop('VIRTUAL_ENV', None)
+
+  # Set by VPython, if scripts want it back they have to set it explicitly.
+  os.environ.pop('PYTHONNOUSERSITE', None)
+
+  # Look for "activate_this.py" in this path, which is installed by VirtualEnv.
+  # This mechanism is used by vpython as well to sanitize VirtualEnvs from
+  # $PATH.
+  os.environ['PATH'] = os.pathsep.join([
+    p for p in os.environ.get('PATH', '').split(os.pathsep)
+    if not os.path.isfile(os.path.join(p, 'activate_this.py'))
+  ])
+
 
 def main(args):
+  # Prune all evidence of VPython/VirtualEnv out of the environment. This means
+  # that we 'unwrap' vpython VirtualEnv path/env manipulation. Invocations of
+  # `python` from GN should never inherit the gn.py's own VirtualEnv. This also
+  # helps to ensure that generated ninja files do not reference python.exe from
+  # the VirtualEnv generated from depot_tools' own .vpython file (or lack
+  # thereof), but instead reference the default python from the PATH.
+  PruneVirtualEnv()
+
   mbw = MetaBuildWrapper()
   return mbw.Main(args)
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index a8b53c1..85130add9 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -9561,6 +9561,18 @@
   <int value="2" label="Aborted"/>
 </enum>
 
+<enum name="ConnectionStateAfterDNS">
+  <int value="0" label="Fresh DNS has failed, close the whole connection."/>
+  <int value="1" label="Resolved IP can be pooled."/>
+  <int value="2"
+      label="Stale connection is waiting for handshake and dns matches."/>
+  <int value="3"
+      label="Stale connection is waiting for handshake but dns doesn't match."/>
+  <int value="4" label="Stale connection finishes handshake and dns matches."/>
+  <int value="5"
+      label="Stale connection finishes handshake but dns doesn't match."/>
+</enum>
+
 <enum name="ConnectionStatus">
   <int value="0" label="Offline"/>
   <int value="1" label="Connected"/>
@@ -11733,6 +11745,7 @@
   <int value="36" label="GET_CONTAINER_SSH_KEYS_FAILED"/>
   <int value="37" label="CONTAINER_EXPORT_IMPORT_CANCELLED"/>
   <int value="38" label="RESTART_ABORTED"/>
+  <int value="39" label="RESTART_FAILED_VM_STOPPED"/>
 </enum>
 
 <enum name="CrostiniSetupResult">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index caed121..f704bf7b 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -78578,6 +78578,17 @@
   </summary>
 </histogram>
 
+<histogram name="Net.QuicSession.ConnectionStateAfterDNS"
+    enum="ConnectionStateAfterDNS" expires_after="2020-06-30">
+  <owner>renjietang@chromium.org</owner>
+  <owner>zhongyi@chromium.org</owner>
+  <summary>
+    Logs the state of the connection from stale host when fresh dns resolution
+    is completed. This histogram is only valid when race_stale_dns_on_connection
+    experiment is enabled.
+  </summary>
+</histogram>
+
 <histogram name="Net.QuicSession.ConnectionTypeFromPeer" enum="AddressFamily"
     expires_after="M77">
   <owner>rch@chromium.org</owner>
@@ -79200,6 +79211,10 @@
 
 <histogram name="Net.QuicSession.SessionAvailableWhenValidatingDNS"
     enum="BooleanAvailable" expires_after="2019-12-31">
+  <obsolete>
+    Deprecated in 9/19 because this metric was added to inspect a crash and the
+    crash had been fixed.
+  </obsolete>
   <owner>renjietang@chromium.org</owner>
   <owner>zhongyi@chromium.org</owner>
   <summary>
@@ -79229,6 +79244,10 @@
 
 <histogram name="Net.QuicSession.StaleHostResolveFailed"
     enum="EmptyStaleResultLocation" expires_after="2019-12-31">
+  <obsolete>
+    Deprecated in 9/19 because this metric was added to inspect a crash and the
+    crash had been fixed.
+  </obsolete>
   <owner>renjietang@chromium.org</owner>
   <owner>zhongyi@chromium.org</owner>
   <summary>
@@ -174544,6 +174563,7 @@
   <suffix name="PinchZoom" label="Pinch-to-zoom interaction"/>
   <suffix name="RAF" label="rAF callback driven animation"/>
   <suffix name="TouchScroll" label="Touchscreen driven interaction"/>
+  <suffix name="Universal" label="All frame production"/>
   <suffix name="WheelScroll" label="Mousewheel driven interaction"/>
   <affected-histogram name="CompositorLatency"/>
   <affected-histogram name="CompositorLatency.MissedFrame"/>
diff --git a/tools/perf/core/story_expectation_validator.py b/tools/perf/core/story_expectation_validator.py
index d2153e0..fac0b065 100755
--- a/tools/perf/core/story_expectation_validator.py
+++ b/tools/perf/core/story_expectation_validator.py
@@ -14,6 +14,8 @@
 path_util.AddTelemetryToPath()
 path_util.AddAndroidPylibToPath()
 
+from telemetry.story.typ_expectations import SYSTEM_CONDITION_TAGS
+
 from typ import expectations_parser as typ_expectations_parser
 
 
@@ -25,7 +27,8 @@
     benchmark_finders.GetBenchmarksInSubDirectory(CLUSTER_TELEMETRY_DIR)
 ]
 MOBILE_PREFIXES = {'android', 'mobile'}
-DESKTOP_PREFIXES = {'chromeos', 'desktop', 'linux', 'mac', 'win'}
+DESKTOP_PREFIXES = {
+    'chromeos', 'desktop', 'linux', 'mac', 'win', 'sierra', 'highsierra'}
 
 
 def is_desktop_tag(tag):
@@ -66,6 +69,19 @@
                "mobile and desktop condition tags") % e.lineno)
 
 
+def validate_tag_declaration_lists(tag_sets):
+  tags_set = set(reduce(lambda x, y: list(x) + list(y), tag_sets))
+  for tag in tags_set:
+    assert tag in SYSTEM_CONDITION_TAGS, (
+        "Tag %s is not in Telemetry's set of allowable condition tags, "
+        "either remove it from expectations.config or add it to Telemetry's "
+        "set of allowable tags." % tag)
+  for tag in SYSTEM_CONDITION_TAGS:
+    assert tag in tags_set, (
+        "Tag %s is not declared in expectations.config, "
+        "please declare it the top of the file" % tag)
+
+
 def main():
   benchmarks = benchmark_finders.GetAllBenchmarks()
   with open(path_util.GetExpectationsPath()) as fp:
@@ -75,6 +91,7 @@
   if ret:
     logging.error(msg)
     return ret
+  validate_tag_declaration_lists(test_expectations.tag_sets)
   validate_story_names(benchmarks, test_expectations)
   validate_expectations_component_tags(test_expectations)
   return 0
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index e9e2590..cbf4ece 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -1,11 +1,12 @@
 # Test Expectation file for telemetry tests.
 # Instructions of how to use this file:
 # https://chromium.googlesource.com/chromium/src/+/master/docs/speed/bot_health_sheriffing/how_to_disable_a_story.md
-
-# tags: [ android android-go android-low-end android-nexus-5 android-nexus-5x
-#         android-nexus-6 android-pixel-2 chromeos desktop linux mac mac-10.12
-#         win win10 win7 ]
-# tags: [ android-not-webview android-webview ]
+# tags: [ android chromeos linux mac mac-10.11 mac-10.12 win win10 win7 sierra highsierra
+#         android-marshmallow android-lollipop android-nougat android-oreo android-pie android-10
+#         android-kitkat ubuntu ]
+# tags: [ android-go android-low-end android-nexus-5 android-nexus-5x android-nexus-6
+#         android-pixel-2 desktop mobile ]
+# tags: [ android-not-webview android-webview android-webview-google android-chromium reference ]
 # results: [ Skip ]
 # conflicts_allowed: True
 
diff --git a/ui/android/java/res/values/attrs.xml b/ui/android/java/res/values/attrs.xml
index c2f1ad33..cabfca89 100644
--- a/ui/android/java/res/values/attrs.xml
+++ b/ui/android/java/res/values/attrs.xml
@@ -8,17 +8,6 @@
     <!-- The top or bottom inset of a drawable. -->
     <attr name="verticalInset" format="reference|dimension"/>
 
-    <declare-styleable name="DualControlLayout">
-        <attr name="stackedMargin" format="reference"/>
-        <attr name="primaryButtonText" format="reference|string"/>
-        <attr name="secondaryButtonText" format="reference|string"/>
-        <attr name="buttonAlignment" format="enum">
-            <enum name="start" value="0" />
-            <enum name="end" value="1" />
-            <enum name="apart" value="2" />
-        </attr>
-    </declare-styleable>
-
     <declare-styleable name="ButtonCompat">
         <!-- The color of the button background. -->
         <attr name="buttonColor" format="color"/>
diff --git a/ui/file_manager/file_manager/background/js/crostini.js b/ui/file_manager/file_manager/background/js/crostini.js
index 822b72a..550a320 100644
--- a/ui/file_manager/file_manager/background/js/crostini.js
+++ b/ui/file_manager/file_manager/background/js/crostini.js
@@ -134,7 +134,6 @@
     // Record UMA.
     const root = this.getRoot_(entry);
     let suffix = CrostiniImpl.VALID_ROOT_TYPES_FOR_SHARE.get(root) ||
-        CrostiniImpl.VALID_DRIVE_FS_ROOT_TYPES_FOR_SHARE.get(root) ||
         CrostiniImpl.UMA_ROOT_TYPE_OTHER;
     metrics.recordSmallCount(
         'CrostiniSharedPaths.Depth.' + suffix,
@@ -267,9 +266,7 @@
       return false;
     }
 
-    return CrostiniImpl.VALID_ROOT_TYPES_FOR_SHARE.has(root) ||
-        (loadTimeData.getBoolean('DRIVE_FS_ENABLED') &&
-         CrostiniImpl.VALID_DRIVE_FS_ROOT_TYPES_FOR_SHARE.has(root));
+    return CrostiniImpl.VALID_ROOT_TYPES_FOR_SHARE.has(root);
   }
 }
 
@@ -295,17 +292,6 @@
   [VolumeManagerCommon.RootType.DOWNLOADS, 'Downloads'],
   [VolumeManagerCommon.RootType.REMOVABLE, 'Removable'],
   [VolumeManagerCommon.RootType.ANDROID_FILES, 'AndroidFiles'],
-]);
-
-/**
- * Can be collapsed into VALID_ROOT_TYPES_FOR_SHARE once
- * DriveFS flag is removed.
- * Keep in sync with histograms.xml:FileBrowserCrostiniSharedPathsDepth
- * histogram_suffix.
- * @type {!Map<?VolumeManagerCommon.RootType, string>}
- * @const
- */
-CrostiniImpl.VALID_DRIVE_FS_ROOT_TYPES_FOR_SHARE = new Map([
   [VolumeManagerCommon.RootType.COMPUTERS_GRAND_ROOT, 'DriveComputers'],
   [VolumeManagerCommon.RootType.COMPUTER, 'DriveComputers'],
   [VolumeManagerCommon.RootType.DRIVE, 'MyDrive'],
diff --git a/ui/file_manager/file_manager/background/js/crostini_unittest.js b/ui/file_manager/file_manager/background/js/crostini_unittest.js
index 785f6ea..67b6a4e 100644
--- a/ui/file_manager/file_manager/background/js/crostini_unittest.js
+++ b/ui/file_manager/file_manager/background/js/crostini_unittest.js
@@ -25,9 +25,7 @@
 function setUp() {
   // Mock LoadTimeData strings.
   window.loadTimeData = {
-    data: {
-      'DRIVE_FS_ENABLED': false,
-    },
+    data: {},
     getBoolean: function(key) {
       return window.loadTimeData.data[key];
     },
@@ -53,14 +51,6 @@
 }
 
 /**
- * Sets the DriveFs enabled state.
- * @param {boolean} enabled
- */
-function setDriveFsEnabled(enabled) {
-  window.loadTimeData.data['DRIVE_FS_ENABLED'] = enabled;
-}
-
-/**
  * Tests init sets crostini and PluginVm enabled status.
  */
 function testInitCrostiniPluginVmEnabled() {
@@ -176,29 +166,6 @@
   const fooFile = new MockEntry(mockFileSystem, '/foo/file');
   const fooFolder = MockDirectoryEntry.create(mockFileSystem, '/foo/folder');
 
-  // Test with DriveFs disabled.
-  setDriveFsEnabled(false);
-  const disallowed = [
-    'computers_grand_root', 'computer', 'drive', 'shared_drives_grand_root',
-    'team_drive', 'test'
-  ];
-  for (const type of disallowed) {
-    volumeManagerRootType =
-        /** @type {!VolumeManagerCommon.RootType<string>} */ (type);
-    assertFalse(crostini.canSharePath('vm', root, true));
-    assertFalse(crostini.canSharePath('vm', root, false));
-    assertFalse(crostini.canSharePath('vm', rootFile, true));
-    assertFalse(crostini.canSharePath('vm', rootFile, false));
-    assertFalse(crostini.canSharePath('vm', rootFolder, true));
-    assertFalse(crostini.canSharePath('vm', rootFolder, false));
-    assertFalse(crostini.canSharePath('vm', fooFile, true));
-    assertFalse(crostini.canSharePath('vm', fooFile, false));
-    assertFalse(crostini.canSharePath('vm', fooFolder, true));
-    assertFalse(crostini.canSharePath('vm', fooFolder, false));
-  }
-
-  // Test with DriveFs enabled.
-  setDriveFsEnabled(true);
   // TODO(crbug.com/917920): Add computers_grand_root and computers when DriveFS
   // enforces allowed write paths.
 
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model.js b/ui/file_manager/file_manager/foreground/js/actions_model.js
index 0ae1a4e0..9b57b9e1 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_model.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_model.js
@@ -113,8 +113,6 @@
     const canShareItem = metadata[0].canShare !== false;
     return this.volumeManager_.getDriveConnectionState().type !==
         VolumeManagerCommon.DriveConnectionType.OFFLINE &&
-        (loadTimeData.getBoolean('DRIVE_FS_ENABLED') ||
-         !util.isTeamDriveRoot(this.entry_)) &&
         canShareItem;
   }
 
@@ -191,16 +189,7 @@
    */
   static create(
       entries, metadataModel, driveSyncHandler, ui, value, onExecute) {
-    if (!loadTimeData.getBoolean('DRIVE_FS_ENABLED')) {
-      if (entries.some((entry) => entry.isDirectory)) {
-        return null;
-      }
-    }
-
     const actionableEntries = entries.filter(entry => {
-      if (entry.isDirectory && !loadTimeData.getBoolean('DRIVE_FS_ENABLED')) {
-        return false;
-      }
       const metadata = metadataModel.getCache([entry], ['hosted', 'pinned'])[0];
       if (metadata.hosted) {
         return false;
@@ -536,9 +525,7 @@
    */
   canExecute() {
     return this.volumeManager_.getDriveConnectionState().type !==
-        VolumeManagerCommon.DriveConnectionType.OFFLINE &&
-        (loadTimeData.getBoolean('DRIVE_FS_ENABLED') ||
-         !util.isTeamDriveRoot(this.entry_));
+        VolumeManagerCommon.DriveConnectionType.OFFLINE;
   }
 
   /**
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js b/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js
index 5e78b74a..52f61fb 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js
@@ -141,7 +141,7 @@
       model.initialize()
           .then(() => {
             const actions = model.getActions();
-            assertEquals(3, Object.keys(actions).length);
+            assertEquals(5, Object.keys(actions).length);
 
             // 'Share' should be disabled in offline mode.
             const shareAction = actions[ActionsModel.CommonActionId.SHARE];
@@ -179,7 +179,7 @@
           })
           .then(() => {
             const actions = model.getActions();
-            assertEquals(4, Object.keys(actions).length);
+            assertEquals(6, Object.keys(actions).length);
             assertTrue(!!actions[ActionsModel.CommonActionId.SHARE]);
             assertTrue(
                 !!actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE]);
@@ -317,18 +317,19 @@
   return reportPromise(
       model.initialize().then(() => {
         const actions = model.getActions();
-        assertEquals(2, Object.keys(actions).length);
+        console.log(Object.keys(actions));
+        assertEquals(4, Object.keys(actions).length);
 
-        // "share" action is disabled for Team Drive Root entries.
+        // "share" action is enabled for Team Drive Root entries.
         const shareAction = actions[ActionsModel.CommonActionId.SHARE];
         assertTrue(!!shareAction);
-        assertFalse(shareAction.canExecute());
+        assertTrue(shareAction.canExecute());
 
         // "manage in drive" action is disabled for Team Drive Root entries.
         const manageAction =
             actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE];
         assertTrue(!!manageAction);
-        assertFalse(manageAction.canExecute());
+        assertTrue(manageAction.canExecute());
       }),
       callback);
 }
@@ -352,13 +353,25 @@
   return reportPromise(
       model.initialize().then(() => {
         const actions = model.getActions();
-        assertEquals(3, Object.keys(actions).length);
+        assertEquals(5, Object.keys(actions).length);
 
         // "Share" is enabled for Team Drive directories.
         const shareAction = actions[ActionsModel.CommonActionId.SHARE];
         assertTrue(!!shareAction);
         assertTrue(shareAction.canExecute());
 
+        // "Available Offline" toggle is enabled for Team Drive directories.
+        const saveForOfflineAction =
+            actions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE];
+        assertTrue(!!saveForOfflineAction);
+        assertTrue(saveForOfflineAction.canExecute());
+
+        // "Available Offline" toggle is enabled for Team Drive directories.
+        const offlineNotNecessaryAction =
+            actions[ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY];
+        assertTrue(!!offlineNotNecessaryAction);
+        assertTrue(offlineNotNecessaryAction.canExecute());
+
         // "Manage in drive" is enabled for Team Drive directories.
         const manageAction =
             actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE];
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
index ee8937e2..4d00aae 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
@@ -31,9 +31,6 @@
 // Set up test components.
 function setUp() {
   // Mock LoadTimeData strings.
-  window.loadTimeData.data = {
-    DRIVE_FS_ENABLED: false,
-  };
   window.loadTimeData.getString = id => id;
 
   const mockTask = /** @type {!chrome.fileManagerPrivate.FileTask} */ ({
diff --git a/ui/file_manager/file_manager/test/crostini_share.js b/ui/file_manager/file_manager/test/crostini_share.js
index 163437f..75c97dc 100644
--- a/ui/file_manager/file_manager/test/crostini_share.js
+++ b/ui/file_manager/file_manager/test/crostini_share.js
@@ -194,8 +194,6 @@
   await test.waitForFiles(
       test.TestEntryInfo.getExpectedRows(test.BASIC_CROSTINI_ENTRY_SET));
 
-  // Set DRIVE_FS_ENABLED=false, and check that 'Share with <VM>' is not shown.
-  loadTimeData.data_['DRIVE_FS_ENABLED'] = false;
   // Check 'Share with <VM>' is not shown in menu.
   assertTrue(
       test.fakeMouseRightClick('#file-list [file-name="A"]'),
@@ -209,16 +207,6 @@
   await test.waitForFiles(
       test.TestEntryInfo.getExpectedRows(test.BASIC_DRIVE_ENTRY_SET));
 
-  // Check 'Share with <VM>' is not shown in menu.
-  assertTrue(test.fakeMouseRightClick(photos), 'right-click photos');
-  await test.waitForElement(menuNoShareWith);
-
-  // Close menu by clicking file-list.
-  assertTrue(test.fakeMouseClick('#file-list'));
-  await test.waitForElement(menuHidden);
-
-  // Set DRIVE_FS_ENABLED=true, and check that 'Share with <VM>' is shown.
-  loadTimeData.data_['DRIVE_FS_ENABLED'] = true;
   // Check 'Share with <VM>' is shown in menu.
   assertTrue(test.fakeMouseRightClick(photos), 'right-click photos');
   await test.waitForElement(menuShareWith);
diff --git a/ui/file_manager/file_manager/test/js/strings.js b/ui/file_manager/file_manager/test/js/strings.js
index f13f44f..110ec7f 100644
--- a/ui/file_manager/file_manager/test/js/strings.js
+++ b/ui/file_manager/file_manager/test/js/strings.js
@@ -11,7 +11,6 @@
 loadTimeData.overrideValues({
   'CROSTINI_ENABLED': true,
   'CROSTINI_ROOT_ACCESS_ALLOWED': true,
-  'DRIVE_FS_ENABLED': true,
   'FEEDBACK_PANEL_ENABLED': false,
   'GOOGLE_DRIVE_REDEEM_URL': 'http://www.google.com/intl/en/chrome/devices' +
       '/goodies.html?utm_source=filesapp&utm_medium=banner&utm_campaign=gsg',