diff --git a/DEPS b/DEPS
index b2d5cc97..cb7f18d2 100644
--- a/DEPS
+++ b/DEPS
@@ -96,7 +96,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': 'ef4f7b4dc1e4c315dab7bd387627cfb9e04bcefd',
+  'skia_revision': 'd31b2f674acc24b44fe68cea872109d96da4c796',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -120,7 +120,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '7e28208d26764438bef62e051d2e1fed13e1e0ec',
+  'pdfium_revision': 'ad18d2fba9dd5833a2e34bfe90c8e3c9a485e805',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -498,7 +498,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '96caad126bb21a8f7593d96fdb0aafdace0183a4',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '0aae1c1fc30a5573c40dda5d9b9242d7fc7c06dd',
       'condition': 'checkout_linux',
   },
 
@@ -523,7 +523,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'b61d387fa2d4e0ea7da1807d2922a4f946343d2d',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '7c3ff1311a4568e3d369c35560ff77b6b2bdef96',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -968,7 +968,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '7c0541da63f571512c49758cbc0767117997a270',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'e1f222e5c5a45f9ec211874e8140dd3f961db3c7', # commit position 21742
+    Var('webrtc_git') + '/src.git' + '@' + 'b4e0e50a2bbf9361bea22f58002ad4c76a719fed', # commit position 21742
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 4ed3e5b..e2ea38d 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -203,6 +203,11 @@
          * @see View#startActivityForResult(Intent, int)
          */
         void super_startActivityForResult(Intent intent, int requestCode);
+
+        /**
+         * @see View#onConfigurationChanged(Configuration)
+         */
+        void super_onConfigurationChanged(Configuration newConfig);
     }
 
     /**
@@ -3432,6 +3437,7 @@
         public void onConfigurationChanged(Configuration newConfig) {
             if (!isDestroyedOrNoOperation(NO_WARN)) {
                 mContentViewCore.onConfigurationChanged(newConfig);
+                mInternalAccessAdapter.super_onConfigurationChanged(newConfig);
             }
         }
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index ceabc8f..19abaed 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -753,6 +753,8 @@
     "system/screen_security/screen_share_observer.h",
     "system/screen_security/screen_share_tray_item.cc",
     "system/screen_security/screen_share_tray_item.h",
+    "system/screen_security/screen_switch_check_controller.cc",
+    "system/screen_security/screen_switch_check_controller.h",
     "system/screen_security/screen_tray_item.cc",
     "system/screen_security/screen_tray_item.h",
     "system/session/logout_button_tray.cc",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 56c0cfc4..07260c9 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -1233,9 +1233,6 @@
       <message name="IDS_ASH_LOGIN_KEYBOARD_SELECTION_SELECT" desc="Label for keyboard selection dropdown">
         Set your keyboard
       </message>
-      <message name="IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_MESSAGE" desc="Text shown in the user pod to remind user that fingerprint unlock is supported">
-        Unlock with fingerprint
-      </message>
 
       <!-- Multi-profiles intro dialog -->
       <message name="IDS_ASH_MULTIPROFILES_INTRO_HEADLINE" desc="Describes which feature multi-profiles intro dialog presents.">
diff --git a/ash/login/login_screen_controller.cc b/ash/login/login_screen_controller.cc
index 19b292ed..c32bca64 100644
--- a/ash/login/login_screen_controller.cc
+++ b/ash/login/login_screen_controller.cc
@@ -382,13 +382,6 @@
   }
 }
 
-void LoginScreenController::SetFingerprintUnlockState(
-    const AccountId& account_id,
-    mojom::FingerprintUnlockState state) {
-  if (DataDispatcher())
-    DataDispatcher()->SetFingerprintUnlockState(account_id, state);
-}
-
 void LoginScreenController::DoAuthenticateUser(const AccountId& account_id,
                                                const std::string& password,
                                                bool authenticated_by_pin,
diff --git a/ash/login/login_screen_controller.h b/ash/login/login_screen_controller.h
index 529bf109..c35c6f3 100644
--- a/ash/login/login_screen_controller.h
+++ b/ash/login/login_screen_controller.h
@@ -123,8 +123,6 @@
       const AccountId& account_id,
       const std::string& locale,
       std::vector<mojom::InputMethodItemPtr> keyboard_layouts) override;
-  void SetFingerprintUnlockState(const AccountId& account_id,
-                                 mojom::FingerprintUnlockState state) override;
 
   // Flushes the mojo pipes - to be used in tests.
   void FlushForTesting();
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc
index aea92784..dcefdf3 100644
--- a/ash/login/ui/lock_contents_view.cc
+++ b/ash/login/ui/lock_contents_view.cc
@@ -392,13 +392,8 @@
   }
 
   // Build user state list.
-  for (const mojom::LoginUserInfoPtr& user : users) {
-    UserState state(user->basic_user_info->account_id);
-    state.fingerprint_state = user->allow_fingerprint_unlock
-                                  ? mojom::FingerprintUnlockState::AVAILABLE
-                                  : mojom::FingerprintUnlockState::UNAVAILABLE;
-    users_.push_back(std::move(state));
-  }
+  for (const mojom::LoginUserInfoPtr& user : users)
+    users_.push_back(UserState{user->basic_user_info->account_id});
 
   auto box_layout =
       std::make_unique<views::BoxLayout>(views::BoxLayout::kHorizontal);
@@ -648,23 +643,6 @@
     GetWidget()->GetFocusManager()->ClearFocus();
 }
 
-void LockContentsView::OnFingerprintUnlockStateChanged(
-    const AccountId& account_id,
-    mojom::FingerprintUnlockState state) {
-  UserState* user_state = FindStateForUser(account_id);
-  if (!user_state)
-    return;
-
-  user_state->fingerprint_state = state;
-  LoginBigUserView* big_view =
-      TryToFindBigUser(account_id, true /*require_auth_active*/);
-  if (!big_view || !big_view->auth_user())
-    return;
-
-  big_view->auth_user()->SetFingerprintState(user_state->fingerprint_state);
-  LayoutAuth(big_view, nullptr /*opt_to_hide*/, true /*animate*/);
-}
-
 void LockContentsView::SetAvatarForUser(const AccountId& account_id,
                                         const mojom::UserAvatarPtr& avatar) {
   auto replace = [&](const ash::mojom::LoginUserInfoPtr& user) {
@@ -1229,17 +1207,10 @@
           GetKeyboardController();
       const bool keyboard_visible =
           keyboard_controller ? keyboard_controller->keyboard_visible() : false;
-      if (state->show_pin && !keyboard_visible &&
-          state->fingerprint_state ==
-              mojom::FingerprintUnlockState::UNAVAILABLE) {
+      if (state->show_pin && !keyboard_visible)
         to_update_auth |= LoginAuthUserView::AUTH_PIN;
-      }
       if (state->enable_tap_auth)
         to_update_auth |= LoginAuthUserView::AUTH_TAP;
-      if (state->fingerprint_state !=
-          mojom::FingerprintUnlockState::UNAVAILABLE) {
-        to_update_auth |= LoginAuthUserView::AUTH_FINGERPRINT;
-      }
     }
     opt_to_update->SetAuthMethods(to_update_auth);
   }
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h
index 55ccb3e..e0748ac 100644
--- a/ash/login/ui/lock_contents_view.h
+++ b/ash/login/ui/lock_contents_view.h
@@ -140,9 +140,6 @@
       const std::vector<mojom::InputMethodItemPtr>& keyboard_layouts) override;
   void OnDetachableBasePairingStatusChanged(
       DetachableBasePairingStatus pairing_status) override;
-  void OnFingerprintUnlockStateChanged(
-      const AccountId& account_id,
-      mojom::FingerprintUnlockState state) override;
 
   // SystemTrayFocusObserver:
   void OnFocusLeavingSystemTray(bool reverse) override;
@@ -177,7 +174,6 @@
     bool enable_tap_auth = false;
     bool force_online_sign_in = false;
     mojom::EasyUnlockIconOptionsPtr easy_unlock_state;
-    mojom::FingerprintUnlockState fingerprint_state;
 
    private:
     DISALLOW_COPY_AND_ASSIGN(UserState);
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index 707fef7..2fecd882 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -56,17 +56,6 @@
 // The color of the online sign-in message text.
 constexpr SkColor kOnlineSignInMessageColor = SkColorSetRGB(0xE6, 0x7C, 0x73);
 
-constexpr SkColor kFingerprintIconViewBorderColor =
-    SkColorSetARGB(0x57, 0xFF, 0xFF, 0xFF);
-constexpr SkColor kFingerprintIconAndTextColor =
-    SkColorSetARGB(0x8A, 0xFF, 0xFF, 0xFF);
-constexpr int kFingerprintIconViewBorderThickness = 1;
-constexpr int kFingerprintIconViewSizeDp = 64;
-constexpr int kFingerprintIconSizeDp = 32;
-constexpr int kResetToDefaultIconColorDelayMs = 500;
-constexpr int kFingerprintIconTopSpacing = 50;
-constexpr int kSpacingBetweenFingerprintIconAndLabel = 20;
-
 // Returns an observer that will hide |view| when it fires. The observer will
 // delete itself after firing. Make sure to call |observer->SetReady()| after
 // attaching it.
@@ -85,112 +74,8 @@
       view));
 }
 
-// A view which has a round border and a fingerprint icon at the center.
-class FingerprintIconView : public views::View {
- public:
-  FingerprintIconView() {
-    SetPreferredSize(
-        gfx::Size(kFingerprintIconViewSizeDp, kFingerprintIconViewSizeDp));
-    icon_ = new views::ImageView;
-    icon_->SetVerticalAlignment(views::ImageView::CENTER);
-    icon_->SetPreferredSize(
-        gfx::Size(kFingerprintIconSizeDp, kFingerprintIconSizeDp));
-    SetIconColor(kFingerprintIconAndTextColor);
-    AddChildView(icon_);
-    SetBorder(views::CreateRoundedRectBorder(
-        kFingerprintIconViewBorderThickness, kFingerprintIconViewSizeDp / 2,
-        kFingerprintIconViewBorderColor));
-  }
-
-  ~FingerprintIconView() override = default;
-
-  // Set color of the icon. The color will be reset to
-  // kFingerprintIconAndTextColor after a short period if different.
-  void SetIconColor(SkColor color) {
-    if (color_ == color)
-      return;
-    color_ = color;
-    reset_icon_color_.Stop();
-    icon_->SetImage(gfx::CreateVectorIcon(kLockScreenFingerprintIcon,
-                                          kFingerprintIconSizeDp, color));
-
-    if (color_ != kFingerprintIconAndTextColor) {
-      reset_icon_color_.Start(
-          FROM_HERE,
-          base::TimeDelta::FromMilliseconds(kResetToDefaultIconColorDelayMs),
-          base::BindRepeating(&FingerprintIconView::SetIconColor,
-                              base::Unretained(this),
-                              kFingerprintIconAndTextColor));
-    }
-  }
-
-  void Layout() override {
-    gfx::Rect icon_bounds = GetContentsBounds();
-    icon_bounds.ClampToCenteredSize(
-        gfx::Size(kFingerprintIconSizeDp, kFingerprintIconSizeDp));
-    icon_->SetBoundsRect(icon_bounds);
-  }
-
- private:
-  views::ImageView* icon_ = nullptr;
-  base::OneShotTimer reset_icon_color_;
-  SkColor color_;
-
-  DISALLOW_COPY_AND_ASSIGN(FingerprintIconView);
-};
-
 }  // namespace
 
-// Consists of fingerprint icon view and a label.
-class LoginAuthUserView::FingerprintView : public views::View {
- public:
-  FingerprintView() {
-    SetPaintToLayer();
-    layer()->SetFillsBoundsOpaquely(false);
-
-    icon_view_ = new FingerprintIconView();
-    AddChildView(icon_view_);
-    label_ = new views::Label(
-        l10n_util::GetStringUTF16(IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_MESSAGE));
-    label_->SetSubpixelRenderingEnabled(false);
-    label_->SetAutoColorReadabilityEnabled(false);
-    label_->SetEnabledColor(kFingerprintIconAndTextColor);
-    AddChildView(label_);
-  }
-
-  void SetIconColor(SkColor color) { icon_view_->SetIconColor(color); }
-
-  void Layout() override {
-    gfx::Rect bounds = GetContentsBounds();
-    icon_view_->SizeToPreferredSize();
-    icon_view_->SetPosition(
-        gfx::Point((bounds.width() - icon_view_->width()) / 2,
-                   bounds.y() + kFingerprintIconTopSpacing));
-    label_->SizeToPreferredSize();
-    label_->SetPosition(
-        gfx::Point(bounds.x(), icon_view_->bounds().bottom() +
-                                   kSpacingBetweenFingerprintIconAndLabel));
-  }
-
-  ~FingerprintView() override = default;
-
-  gfx::Size CalculatePreferredSize() const override {
-    int preferred_height = label_->GetPreferredSize().height() +
-                           icon_view_->GetPreferredSize().height() +
-                           kFingerprintIconTopSpacing +
-                           kSpacingBetweenFingerprintIconAndLabel;
-    int preferred_width = std::max(label_->GetPreferredSize().width(),
-                                   icon_view_->GetPreferredSize().width());
-    return gfx::Size(preferred_width, preferred_height);
-  }
-
- private:
-  FingerprintIconView* icon_view_ = nullptr;
-  views::Label* label_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(FingerprintView);
-};
-
 struct LoginAuthUserView::AnimationState {
   int non_pin_y_start_in_screen = 0;
   gfx::Point pin_start_in_screen;
@@ -280,8 +165,6 @@
       this, base::UTF8ToUTF16(user->basic_user_info->display_name));
   DecorateOnlineSignInMessage();
 
-  fingerprint_view_ = new FingerprintView();
-
   SetPaintToLayer(ui::LayerType::LAYER_NOT_DRAWN);
 
   // Build layout.
@@ -293,13 +176,10 @@
       login_layout_util::WrapViewForPreferredSize(user_view_);
   auto* wrapped_pin_view =
       login_layout_util::WrapViewForPreferredSize(pin_view_);
-  auto* wrapped_fingerprint_view =
-      login_layout_util::WrapViewForPreferredSize(fingerprint_view_);
 
   // Add views in tabbing order; they are rendered in a different order below.
   AddChildView(wrapped_password_view);
   AddChildView(wrapped_message_view);
-  AddChildView(wrapped_fingerprint_view);
   AddChildView(wrapped_pin_view);
   AddChildView(wrapped_user_view);
 
@@ -326,7 +206,6 @@
   add_view(wrapped_password_view);
   add_view(wrapped_message_view);
   add_padding(kDistanceBetweenPasswordFieldAndPinKeyboard);
-  add_view(wrapped_fingerprint_view);
   add_view(wrapped_pin_view);
   add_padding(kDistanceFromPinKeyboardToBigUserViewBottom);
 
@@ -345,7 +224,6 @@
   bool has_pin = HasAuthMethod(AUTH_PIN);
   bool has_tap = HasAuthMethod(AUTH_TAP);
   bool force_online_sign_in = HasAuthMethod(AUTH_ONLINE_SIGN_IN);
-  bool has_fingerprint = HasAuthMethod(AUTH_FINGERPRINT);
 
   online_sign_in_message_->SetVisible(force_online_sign_in);
 
@@ -358,7 +236,6 @@
     password_view_->RequestFocus();
 
   pin_view_->SetVisible(has_pin);
-  fingerprint_view_->SetVisible(has_fingerprint);
 
   // Note: if both |has_tap| and |has_pin| are true, prefer tap placeholder.
   if (has_tap) {
@@ -491,20 +368,6 @@
       base::UTF8ToUTF16(user->basic_user_info->display_name));
 }
 
-void LoginAuthUserView::SetFingerprintState(
-    mojom::FingerprintUnlockState state) {
-  fingerprint_view_->SetVisible(state !=
-                                mojom::FingerprintUnlockState::UNAVAILABLE);
-
-  SkColor color = kFingerprintIconAndTextColor;
-  if (state == mojom::FingerprintUnlockState::AUTH_SUCCESS) {
-    color = SK_ColorBLUE;
-  } else if (state == mojom::FingerprintUnlockState::AUTH_FAILED) {
-    color = SK_ColorRED;
-  }
-  fingerprint_view_->SetIconColor(color);
-}
-
 const mojom::LoginUserInfoPtr& LoginAuthUserView::current_user() const {
   return user_view_->current_user();
 }
diff --git a/ash/login/ui/login_auth_user_view.h b/ash/login/ui/login_auth_user_view.h
index 5c218626..e38348ca 100644
--- a/ash/login/ui/login_auth_user_view.h
+++ b/ash/login/ui/login_auth_user_view.h
@@ -82,7 +82,6 @@
     AUTH_PIN = 1 << 1,             // Display PIN keyboard.
     AUTH_TAP = 1 << 2,             // Tap to unlock.
     AUTH_ONLINE_SIGN_IN = 1 << 3,  // Force online sign-in.
-    AUTH_FINGERPRINT = 1 << 4,     // Use fingerprint to unlock.
   };
 
   LoginAuthUserView(const mojom::LoginUserInfoPtr& user,
@@ -108,8 +107,6 @@
   // Update the displayed name, icon, etc to that of |user|.
   void UpdateForUser(const mojom::LoginUserInfoPtr& user);
 
-  void SetFingerprintState(mojom::FingerprintUnlockState state);
-
   const mojom::LoginUserInfoPtr& current_user() const;
 
   LoginPasswordView* password_view() { return password_view_; }
@@ -124,7 +121,6 @@
 
  private:
   struct AnimationState;
-  class FingerprintView;
 
   // Called when the user submits an auth method. Runs mojo call.
   void OnAuthSubmit(const base::string16& password);
@@ -151,7 +147,6 @@
   LoginPasswordView* password_view_ = nullptr;
   LoginPinView* pin_view_ = nullptr;
   views::LabelButton* online_sign_in_message_ = nullptr;
-  FingerprintView* fingerprint_view_ = nullptr;
   const OnAuthCallback on_auth_;
   const LoginUserView::OnTap on_tap_;
 
diff --git a/ash/login/ui/login_data_dispatcher.cc b/ash/login/ui/login_data_dispatcher.cc
index bc440cfd..0a4e7efa 100644
--- a/ash/login/ui/login_data_dispatcher.cc
+++ b/ash/login/ui/login_data_dispatcher.cc
@@ -52,10 +52,6 @@
 void LoginDataDispatcher::Observer::OnDetachableBasePairingStatusChanged(
     DetachableBasePairingStatus pairing_status) {}
 
-void LoginDataDispatcher::Observer::OnFingerprintUnlockStateChanged(
-    const AccountId& account_id,
-    mojom::FingerprintUnlockState state) {}
-
 LoginDataDispatcher::LoginDataDispatcher() = default;
 
 LoginDataDispatcher::~LoginDataDispatcher() = default;
@@ -147,11 +143,4 @@
     observer.OnDetachableBasePairingStatusChanged(pairing_status);
 }
 
-void LoginDataDispatcher::SetFingerprintUnlockState(
-    const AccountId& account_id,
-    mojom::FingerprintUnlockState state) {
-  for (auto& observer : observers_)
-    observer.OnFingerprintUnlockStateChanged(account_id, state);
-}
-
 }  // namespace ash
diff --git a/ash/login/ui/login_data_dispatcher.h b/ash/login/ui/login_data_dispatcher.h
index 1836980e..b360775 100644
--- a/ash/login/ui/login_data_dispatcher.h
+++ b/ash/login/ui/login_data_dispatcher.h
@@ -96,11 +96,6 @@
     // base is attached or detached.
     virtual void OnDetachableBasePairingStatusChanged(
         DetachableBasePairingStatus pairing_status);
-
-    // Called when fingerprint unlock state changes for user with |account_id|.
-    virtual void OnFingerprintUnlockStateChanged(
-        const AccountId& account_id,
-        mojom::FingerprintUnlockState state);
   };
 
   LoginDataDispatcher();
@@ -131,8 +126,6 @@
       const std::vector<mojom::InputMethodItemPtr>& keyboard_layouts);
   void SetDetachableBasePairingStatus(
       DetachableBasePairingStatus pairing_status);
-  void SetFingerprintUnlockState(const AccountId& account_id,
-                                 mojom::FingerprintUnlockState state);
 
  private:
   base::ObserverList<Observer> observers_;
diff --git a/ash/public/interfaces/login_screen.mojom b/ash/public/interfaces/login_screen.mojom
index d2e5a0a..0eb58f2 100644
--- a/ash/public/interfaces/login_screen.mojom
+++ b/ash/public/interfaces/login_screen.mojom
@@ -112,10 +112,6 @@
   SetPublicSessionKeyboardLayouts(signin.mojom.AccountId account_id,
                                   string locale,
                                   array<InputMethodItem> keyboard_layouts);
-
-  // Set the fingerprint unlock state for user with |account_id|.
-  SetFingerprintUnlockState(signin.mojom.AccountId account_id,
-                            FingerprintUnlockState state);
 };
 
 // Allows ash lock screen to control a client (e.g. Chrome browser). Requests
diff --git a/ash/public/interfaces/login_user_info.mojom b/ash/public/interfaces/login_user_info.mojom
index 6bee6bde..150897e9 100644
--- a/ash/public/interfaces/login_user_info.mojom
+++ b/ash/public/interfaces/login_user_info.mojom
@@ -38,18 +38,6 @@
   SPINNER,
 };
 
-// Fingerprint unlock state in the views lock screen.
-enum FingerprintUnlockState {
-  // Fingerprint unlock is not available.
-  UNAVAILABLE,
-  // Fingerprint unlock is available.
-  AVAILABLE,
-  // The unlock attempt is successful, the fingerprint is matched.
-  AUTH_SUCCESS,
-  // The unlock attempt is unsuccessful, the fingerprint is not recognized.
-  AUTH_FAILED,
-};
-
 // Information about the custom icon in the user pod.
 struct EasyUnlockIconOptions {
   // Icon that should be displayed.
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 24a1846..d110d52 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -22,7 +22,6 @@
     "lock_screen_backspace.icon",
     "lock_screen_caps_lock.icon",
     "lock_screen_dropdown.icon",
-    "lock_screen_fingerprint.icon",
     "login_screen_button_dropdown.icon",
     "login_screen_menu_dropdown.icon",
     "login_screen_enterprise.icon",
diff --git a/ash/resources/vector_icons/lock_screen_fingerprint.icon b/ash/resources/vector_icons/lock_screen_fingerprint.icon
deleted file mode 100644
index 5fc5ed7..0000000
--- a/ash/resources/vector_icons/lock_screen_fingerprint.icon
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 54,
-MOVE_TO, 40.07f, 10.06f,
-CUBIC_TO, 39.89f, 10.06f, 39.72f, 10.01f, 39.56f, 9.93f,
-CUBIC_TO, 35.25f, 7.71f, 31.5f, 6.75f, 27.02f, 6.75f,
-CUBIC_TO, 22.56f, 6.75f, 18.35f, 7.82f, 14.49f, 9.92f,
-CUBIC_TO, 13.94f, 10.22f, 13.26f, 10.02f, 12.96f, 9.47f,
-CUBIC_TO, 12.67f, 8.92f, 12.86f, 8.25f, 13.41f, 7.94f,
-CUBIC_TO, 17.61f, 5.66f, 22.19f, 4.5f, 27.02f, 4.5f,
-CUBIC_TO, 31.82f, 4.5f, 36, 5.56f, 40.59f, 7.93f,
-CUBIC_TO, 41.14f, 8.21f, 41.36f, 8.9f, 41.07f, 9.45f,
-CUBIC_TO, 40.87f, 9.83f, 40.48f, 10.06f, 40.07f, 10.06f,
-LINE_TO, 40.07f, 10.06f,
-CLOSE,
-MOVE_TO, 7.88f, 21.87f,
-CUBIC_TO, 7.65f, 21.87f, 7.43f, 21.8f, 7.22f, 21.67f,
-CUBIC_TO, 6.72f, 21.31f, 6.59f, 20.61f, 6.95f, 20.1f,
-CUBIC_TO, 9.18f, 16.95f, 12.03f, 14.48f, 15.4f, 12.74f,
-CUBIC_TO, 22.48f, 9.08f, 31.52f, 9.07f, 38.61f, 12.71f,
-CUBIC_TO, 41.97f, 14.45f, 44.81f, 16.9f, 47.05f, 20.02f,
-CUBIC_TO, 47.41f, 20.53f, 47.3f, 21.23f, 46.79f, 21.59f,
-CUBIC_TO, 46.28f, 21.95f, 45.57f, 21.84f, 45.21f, 21.33f,
-CUBIC_TO, 43.19f, 18.5f, 40.62f, 16.27f, 37.59f, 14.72f,
-CUBIC_TO, 31.13f, 11.4f, 22.88f, 11.41f, 16.44f, 14.74f,
-CUBIC_TO, 13.39f, 16.31f, 10.81f, 18.55f, 8.8f, 21.41f,
-CUBIC_TO, 8.57f, 21.71f, 8.22f, 21.87f, 7.88f, 21.87f,
-LINE_TO, 7.88f, 21.87f,
-CLOSE,
-MOVE_TO, 21.95f, 49.02f,
-CUBIC_TO, 21.66f, 49.02f, 21.38f, 48.9f, 21.15f, 48.68f,
-CUBIC_TO, 19.2f, 46.71f, 18.15f, 45.46f, 16.63f, 42.75f,
-CUBIC_TO, 15.08f, 39.98f, 14.25f, 36.6f, 14.25f, 32.97f,
-CUBIC_TO, 14.25f, 26.29f, 19.97f, 20.85f, 27, 20.85f,
-CUBIC_TO, 34.03f, 20.85f, 39.75f, 26.28f, 39.75f, 32.97f,
-CUBIC_TO, 39.75f, 33.59f, 39.24f, 34.1f, 38.62f, 34.1f,
-CUBIC_TO, 38, 34.1f, 37.5f, 33.59f, 37.5f, 32.97f,
-CUBIC_TO, 37.5f, 27.53f, 32.79f, 23.1f, 27, 23.1f,
-CUBIC_TO, 21.22f, 23.1f, 16.5f, 27.53f, 16.5f, 32.97f,
-CUBIC_TO, 16.5f, 36.21f, 17.22f, 39.21f, 18.59f, 41.65f,
-CUBIC_TO, 20.04f, 44.24f, 21, 45.35f, 22.74f, 47.09f,
-CUBIC_TO, 23.18f, 47.53f, 23.18f, 48.25f, 22.73f, 48.68f,
-CUBIC_TO, 22.52f, 48.92f, 22.23f, 49.02f, 21.95f, 49.02f,
-LINE_TO, 21.95f, 49.02f,
-CLOSE,
-MOVE_TO, 38.07f, 44.85f,
-CUBIC_TO, 35.39f, 44.85f, 33.04f, 44.18f, 31.1f, 42.86f,
-CUBIC_TO, 27.75f, 40.59f, 25.75f, 36.9f, 25.75f, 32.99f,
-CUBIC_TO, 25.75f, 32.37f, 26.26f, 31.86f, 26.88f, 31.86f,
-CUBIC_TO, 27.5f, 31.86f, 28, 32.37f, 28, 32.99f,
-CUBIC_TO, 28, 36.15f, 29.63f, 39.14f, 32.37f, 41,
-CUBIC_TO, 33.95f, 42.08f, 35.82f, 42.6f, 38.07f, 42.6f,
-CUBIC_TO, 38.61f, 42.6f, 39.52f, 42.55f, 40.42f, 42.39f,
-CUBIC_TO, 41.03f, 42.28f, 41.61f, 42.69f, 41.73f, 43.3f,
-CUBIC_TO, 41.84f, 43.91f, 41.42f, 44.49f, 40.82f, 44.61f,
-CUBIC_TO, 39.5f, 44.84f, 38.39f, 44.85f, 38.07f, 44.85f,
-LINE_TO, 38.07f, 44.85f,
-CLOSE,
-MOVE_TO, 33.54f, 49.5f,
-CUBIC_TO, 33.44f, 49.5f, 33.33f, 49.49f, 33.24f, 49.46f,
-CUBIC_TO, 29.66f, 48.48f, 27.32f, 47.15f, 24.89f, 44.73f,
-CUBIC_TO, 21.75f, 41.6f, 20.01f, 37.43f, 20.01f, 32.99f,
-CUBIC_TO, 20.01f, 29.33f, 23.12f, 26.36f, 26.94f, 26.36f,
-CUBIC_TO, 30.77f, 26.36f, 33.87f, 29.33f, 33.87f, 32.99f,
-CUBIC_TO, 33.87f, 35.39f, 35.98f, 37.36f, 38.55f, 37.36f,
-CUBIC_TO, 41.13f, 37.36f, 43.23f, 35.4f, 43.23f, 32.99f,
-CUBIC_TO, 43.23f, 24.5f, 35.92f, 17.61f, 26.93f, 17.61f,
-CUBIC_TO, 20.53f, 17.61f, 14.69f, 21.16f, 12.06f, 26.67f,
-CUBIC_TO, 11.18f, 28.5f, 10.74f, 30.62f, 10.74f, 32.99f,
-CUBIC_TO, 10.74f, 34.74f, 10.9f, 37.51f, 12.24f, 41.1f,
-CUBIC_TO, 12.45f, 41.68f, 12.16f, 42.32f, 11.58f, 42.55f,
-CUBIC_TO, 10.99f, 42.76f, 10.35f, 42.47f, 10.13f, 41.88f,
-CUBIC_TO, 9.02f, 38.92f, 8.48f, 36.02f, 8.48f, 32.99f,
-CUBIC_TO, 8.48f, 30.29f, 9, 27.83f, 10.02f, 25.71f,
-CUBIC_TO, 13.03f, 19.43f, 19.67f, 15.37f, 26.92f, 15.37f,
-CUBIC_TO, 37.15f, 15.37f, 45.47f, 23.28f, 45.47f, 33,
-CUBIC_TO, 45.47f, 36.65f, 42.36f, 39.62f, 38.54f, 39.62f,
-CUBIC_TO, 34.73f, 39.62f, 31.61f, 36.65f, 31.61f, 33,
-CUBIC_TO, 31.61f, 30.59f, 29.51f, 28.62f, 26.93f, 28.62f,
-CUBIC_TO, 24.36f, 28.62f, 22.25f, 30.58f, 22.25f, 33,
-CUBIC_TO, 22.25f, 36.83f, 23.75f, 40.44f, 26.46f, 43.14f,
-CUBIC_TO, 28.59f, 45.26f, 30.66f, 46.43f, 33.83f, 47.3f,
-CUBIC_TO, 34.42f, 47.46f, 34.78f, 48.08f, 34.62f, 48.68f,
-CUBIC_TO, 34.48f, 49.17f, 34.03f, 49.5f, 33.54f, 49.5f,
-LINE_TO, 33.54f, 49.5f,
-CLOSE
-
-CANVAS_DIMENSIONS, 27,
-MOVE_TO, 20.04f, 5.03f,
-CUBIC_TO, 19.95f, 5.03f, 19.86f, 5.01f, 19.78f, 4.97f,
-CUBIC_TO, 17.62f, 3.85f, 15.75f, 3.38f, 13.51f, 3.38f,
-CUBIC_TO, 11.28f, 3.38f, 9.17f, 3.91f, 7.25f, 4.96f,
-CUBIC_TO, 6.97f, 5.11f, 6.63f, 5.01f, 6.48f, 4.74f,
-CUBIC_TO, 6.33f, 4.46f, 6.43f, 4.12f, 6.71f, 3.97f,
-CUBIC_TO, 8.8f, 2.83f, 11.09f, 2.25f, 13.51f, 2.25f,
-CUBIC_TO, 15.91f, 2.25f, 18, 2.78f, 20.3f, 3.97f,
-CUBIC_TO, 20.57f, 4.11f, 20.68f, 4.45f, 20.54f, 4.72f,
-CUBIC_TO, 20.44f, 4.92f, 20.24f, 5.03f, 20.04f, 5.03f,
-LINE_TO, 20.04f, 5.03f,
-CLOSE,
-MOVE_TO, 3.94f, 10.94f,
-CUBIC_TO, 3.83f, 10.94f, 3.71f, 10.9f, 3.61f, 10.83f,
-CUBIC_TO, 3.36f, 10.65f, 3.3f, 10.31f, 3.48f, 10.05f,
-CUBIC_TO, 4.59f, 8.48f, 6.01f, 7.24f, 7.7f, 6.37f,
-CUBIC_TO, 11.24f, 4.54f, 15.76f, 4.53f, 19.31f, 6.36f,
-CUBIC_TO, 20.99f, 7.22f, 22.4f, 8.45f, 23.52f, 10.01f,
-CUBIC_TO, 23.7f, 10.27f, 23.65f, 10.61f, 23.39f, 10.79f,
-CUBIC_TO, 23.14f, 10.97f, 22.79f, 10.92f, 22.61f, 10.67f,
-CUBIC_TO, 21.59f, 9.25f, 20.31f, 8.13f, 18.79f, 7.36f,
-CUBIC_TO, 15.56f, 5.7f, 11.44f, 5.7f, 8.22f, 7.37f,
-CUBIC_TO, 6.69f, 8.16f, 5.41f, 9.28f, 4.4f, 10.7f,
-CUBIC_TO, 4.29f, 10.86f, 4.11f, 10.94f, 3.94f, 10.94f,
-LINE_TO, 3.94f, 10.94f,
-CLOSE,
-MOVE_TO, 10.97f, 24.51f,
-CUBIC_TO, 10.83f, 24.51f, 10.69f, 24.45f, 10.58f, 24.34f,
-CUBIC_TO, 9.6f, 23.36f, 9.07f, 22.73f, 8.31f, 21.38f,
-CUBIC_TO, 7.54f, 19.99f, 7.13f, 18.3f, 7.13f, 16.49f,
-CUBIC_TO, 7.13f, 13.15f, 9.98f, 10.42f, 13.5f, 10.42f,
-CUBIC_TO, 17.02f, 10.42f, 19.87f, 13.14f, 19.87f, 16.49f,
-CUBIC_TO, 19.87f, 16.8f, 19.62f, 17.05f, 19.31f, 17.05f,
-CUBIC_TO, 19, 17.05f, 18.75f, 16.8f, 18.75f, 16.49f,
-CUBIC_TO, 18.75f, 13.76f, 16.4f, 11.55f, 13.5f, 11.55f,
-CUBIC_TO, 10.61f, 11.55f, 8.25f, 13.76f, 8.25f, 16.49f,
-CUBIC_TO, 8.25f, 18.11f, 8.61f, 19.6f, 9.29f, 20.82f,
-CUBIC_TO, 10.02f, 22.12f, 10.5f, 22.67f, 11.37f, 23.55f,
-CUBIC_TO, 11.59f, 23.77f, 11.59f, 24.13f, 11.36f, 24.34f,
-CUBIC_TO, 11.26f, 24.46f, 11.12f, 24.51f, 10.97f, 24.51f,
-LINE_TO, 10.97f, 24.51f,
-CLOSE,
-MOVE_TO, 19.04f, 22.43f,
-CUBIC_TO, 17.7f, 22.43f, 16.52f, 22.09f, 15.55f, 21.43f,
-CUBIC_TO, 13.88f, 20.3f, 12.88f, 18.45f, 12.88f, 16.49f,
-CUBIC_TO, 12.88f, 16.18f, 13.13f, 15.93f, 13.44f, 15.93f,
-CUBIC_TO, 13.75f, 15.93f, 14, 16.18f, 14, 16.49f,
-CUBIC_TO, 14, 18.07f, 14.82f, 19.57f, 16.18f, 20.5f,
-CUBIC_TO, 16.98f, 21.04f, 17.91f, 21.3f, 19.04f, 21.3f,
-CUBIC_TO, 19.31f, 21.3f, 19.76f, 21.27f, 20.21f, 21.2f,
-CUBIC_TO, 20.51f, 21.14f, 20.81f, 21.35f, 20.86f, 21.65f,
-CUBIC_TO, 20.92f, 21.95f, 20.71f, 22.25f, 20.41f, 22.3f,
-CUBIC_TO, 19.75f, 22.42f, 19.19f, 22.43f, 19.04f, 22.43f,
-LINE_TO, 19.04f, 22.43f,
-CLOSE,
-MOVE_TO, 16.77f, 24.75f,
-CUBIC_TO, 16.72f, 24.75f, 16.67f, 24.74f, 16.62f, 24.73f,
-CUBIC_TO, 14.83f, 24.24f, 13.66f, 23.57f, 12.44f, 22.37f,
-CUBIC_TO, 10.87f, 20.8f, 10.01f, 18.71f, 10.01f, 16.49f,
-CUBIC_TO, 10.01f, 14.66f, 11.56f, 13.18f, 13.47f, 13.18f,
-CUBIC_TO, 15.38f, 13.18f, 16.94f, 14.66f, 16.94f, 16.49f,
-CUBIC_TO, 16.94f, 17.7f, 17.99f, 18.68f, 19.28f, 18.68f,
-CUBIC_TO, 20.57f, 18.68f, 21.62f, 17.7f, 21.62f, 16.49f,
-CUBIC_TO, 21.62f, 12.25f, 17.96f, 8.8f, 13.47f, 8.8f,
-CUBIC_TO, 10.27f, 8.8f, 7.35f, 10.58f, 6.03f, 13.34f,
-CUBIC_TO, 5.59f, 14.25f, 5.37f, 15.31f, 5.37f, 16.49f,
-CUBIC_TO, 5.37f, 17.37f, 5.45f, 18.75f, 6.12f, 20.55f,
-CUBIC_TO, 6.23f, 20.84f, 6.08f, 21.16f, 5.79f, 21.27f,
-CUBIC_TO, 5.5f, 21.38f, 5.18f, 21.23f, 5.06f, 20.94f,
-CUBIC_TO, 4.51f, 19.46f, 4.24f, 18.01f, 4.24f, 16.49f,
-CUBIC_TO, 4.24f, 15.14f, 4.5f, 13.92f, 5.01f, 12.85f,
-CUBIC_TO, 6.51f, 9.71f, 9.83f, 7.68f, 13.46f, 7.68f,
-CUBIC_TO, 18.57f, 7.68f, 22.74f, 11.64f, 22.74f, 16.5f,
-CUBIC_TO, 22.74f, 18.33f, 21.18f, 19.81f, 19.27f, 19.81f,
-CUBIC_TO, 17.36f, 19.81f, 15.81f, 18.33f, 15.81f, 16.5f,
-CUBIC_TO, 15.81f, 15.29f, 14.75f, 14.31f, 13.47f, 14.31f,
-CUBIC_TO, 12.18f, 14.31f, 11.13f, 15.29f, 11.13f, 16.5f,
-CUBIC_TO, 11.13f, 18.42f, 11.87f, 20.22f, 13.23f, 21.57f,
-CUBIC_TO, 14.29f, 22.63f, 15.33f, 23.21f, 16.91f, 23.65f,
-CUBIC_TO, 17.21f, 23.73f, 17.39f, 24.04f, 17.31f, 24.34f,
-CUBIC_TO, 17.24f, 24.59f, 17.02f, 24.75f, 16.77f, 24.75f,
-LINE_TO, 16.77f, 24.75f,
-CLOSE
-
diff --git a/ash/session/session_controller.cc b/ash/session/session_controller.cc
index 0752bfb..1880f3d 100644
--- a/ash/session/session_controller.cc
+++ b/ash/session/session_controller.cc
@@ -17,7 +17,7 @@
 #include "ash/session/teleport_warning_dialog.h"
 #include "ash/shell.h"
 #include "ash/system/power/power_event_observer.h"
-#include "ash/system/tray/system_tray.h"
+#include "ash/system/screen_security/screen_switch_check_controller.h"
 #include "ash/wm/lock_state_controller.h"
 #include "ash/wm/overview/window_selector_controller.h"
 #include "ash/wm/window_state.h"
@@ -417,8 +417,9 @@
   if (controller->IsSelecting())
     controller->ToggleOverview();
 
-  ash::Shell::Get()->GetPrimarySystemTray()->CanSwitchAwayFromActiveUser(
-      std::move(callback));
+  ash::Shell::Get()
+      ->screen_switch_check_controller()
+      ->CanSwitchAwayFromActiveUser(std::move(callback));
 }
 
 void SessionController::ShowMultiprofilesIntroDialog(
diff --git a/ash/session/session_controller_unittest.cc b/ash/session/session_controller_unittest.cc
index 20fb1d34..7e4bf24 100644
--- a/ash/session/session_controller_unittest.cc
+++ b/ash/session/session_controller_unittest.cc
@@ -17,7 +17,7 @@
 #include "ash/shell.h"
 #include "ash/system/message_center/notification_tray.h"
 #include "ash/system/screen_security/screen_tray_item.h"
-#include "ash/system/tray/system_tray.h"
+#include "ash/system/tray/system_tray_notifier.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/overview/window_selector_controller.h"
 #include "ash/wm/window_util.h"
@@ -559,11 +559,6 @@
 
   void SetUp() override {
     AshTestBase::SetUp();
-    SystemTray* system_tray = GetPrimarySystemTray();
-    share_item_ = system_tray->GetScreenShareItem();
-    capture_item_ = system_tray->GetScreenCaptureItem();
-    EXPECT_TRUE(share_item_);
-    EXPECT_TRUE(capture_item_);
     NotificationTray::DisableAnimationsForTest(true);
   }
 
@@ -576,12 +571,16 @@
   // Accessing the capture session functionality.
   // Simulates a screen capture session start.
   void StartCaptureSession() {
-    capture_item_->Start(base::Bind(&CanSwitchUserTest::StopCaptureCallback,
-                                    base::Unretained(this)));
+    Shell::Get()->system_tray_notifier()->NotifyScreenCaptureStart(
+        base::BindRepeating(&CanSwitchUserTest::StopCaptureCallback,
+                            base::Unretained(this)),
+        base::EmptyString16());
   }
 
   // The callback which gets called when the screen capture gets stopped.
-  void StopCaptureSession() { capture_item_->Stop(); }
+  void StopCaptureSession() {
+    Shell::Get()->system_tray_notifier()->NotifyScreenCaptureStop();
+  }
 
   // Simulates a screen capture session stop.
   void StopCaptureCallback() { stop_capture_callback_hit_count_++; }
@@ -589,12 +588,16 @@
   // Accessing the share session functionality.
   // Simulate a Screen share session start.
   void StartShareSession() {
-    share_item_->Start(base::Bind(&CanSwitchUserTest::StopShareCallback,
-                                  base::Unretained(this)));
+    Shell::Get()->system_tray_notifier()->NotifyScreenShareStart(
+        base::BindRepeating(&CanSwitchUserTest::StopShareCallback,
+                            base::Unretained(this)),
+        base::EmptyString16());
   }
 
   // Simulates a screen share session stop.
-  void StopShareSession() { share_item_->Stop(); }
+  void StopShareSession() {
+    Shell::Get()->system_tray_notifier()->NotifyScreenShareStop();
+  }
 
   // The callback which gets called when the screen share gets stopped.
   void StopShareCallback() { stop_share_callback_hit_count_++; }
@@ -657,11 +660,6 @@
     }
   }
 
-  // The two items from the SystemTray for the screen capture / share
-  // functionality.
-  ScreenTrayItem* capture_item_ = nullptr;
-  ScreenTrayItem* share_item_ = nullptr;
-
   // Various counters to query for.
   int stop_capture_callback_hit_count_ = 0;
   int stop_share_callback_hit_count_ = 0;
diff --git a/ash/shell.cc b/ash/shell.cc
index 17736e4..7e0bd31 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -107,6 +107,7 @@
 #include "ash/system/power/power_status.h"
 #include "ash/system/power/video_activity_notifier.h"
 #include "ash/system/screen_layout_observer.h"
+#include "ash/system/screen_security/screen_switch_check_controller.h"
 #include "ash/system/session/logout_button_tray.h"
 #include "ash/system/session/logout_confirmation_controller.h"
 #include "ash/system/status_area_widget.h"
@@ -862,6 +863,8 @@
   voice_interaction_controller_.reset();
   key_accessibility_enabler_.reset();
 
+  screen_switch_check_controller_.reset();
+
   // This also deletes all RootWindows. Note that we invoke Shutdown() on
   // WindowTreeHostManager before resetting |window_tree_host_manager_|, since
   // destruction of its owned RootWindowControllers relies on the value.
@@ -963,6 +966,8 @@
   detachable_base_notification_controller_ =
       std::make_unique<DetachableBaseNotificationController>(
           detachable_base_handler_.get());
+  screen_switch_check_controller_ =
+      std::make_unique<ScreenSwitchCheckController>();
   // Connector can be null in tests.
   if (shell_delegate_->GetShellConnector() &&
       base::FeatureList::IsEnabled(
diff --git a/ash/shell.h b/ash/shell.h
index 75a7f6d..2b6061f 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -151,6 +151,7 @@
 class ScreenshotController;
 class ScreenPinningController;
 class ScreenPositionController;
+class ScreenSwitchCheckController;
 class SessionController;
 class ShelfController;
 class ShelfModel;
@@ -479,6 +480,9 @@
   ScreenPinningController* screen_pinning_controller() {
     return screen_pinning_controller_.get();
   }
+  ScreenSwitchCheckController* screen_switch_check_controller() {
+    return screen_switch_check_controller_.get();
+  }
   SessionController* session_controller() { return session_controller_.get(); }
   ::wm::ShadowController* shadow_controller() {
     return shadow_controller_.get();
@@ -746,6 +750,7 @@
   std::unique_ptr<SessionController> session_controller_;
   std::unique_ptr<NightLightController> night_light_controller_;
   std::unique_ptr<NoteTakingController> note_taking_controller_;
+  std::unique_ptr<ScreenSwitchCheckController> screen_switch_check_controller_;
   std::unique_ptr<ShelfController> shelf_controller_;
   std::unique_ptr<ShelfWindowWatcher> shelf_window_watcher_;
   std::unique_ptr<ShellDelegate> shell_delegate_;
diff --git a/ash/system/power/tray_power.cc b/ash/system/power/tray_power.cc
index 82a2020e..630e6d8 100644
--- a/ash/system/power/tray_power.cc
+++ b/ash/system/power/tray_power.cc
@@ -39,55 +39,50 @@
 
 namespace tray {
 
-// This view is used only for the tray.
-class PowerTrayView : public TrayItemView {
- public:
-  explicit PowerTrayView(SystemTrayItem* owner) : TrayItemView(owner) {
-    CreateImageView();
-    UpdateImage();
-  }
+PowerTrayView::PowerTrayView(SystemTrayItem* owner) : TrayItemView(owner) {
+  CreateImageView();
+  UpdateImage();
+  UpdateStatus();
+  PowerStatus::Get()->AddObserver(this);
+}
 
-  ~PowerTrayView() override = default;
+PowerTrayView::~PowerTrayView() {
+  PowerStatus::Get()->RemoveObserver(this);
+}
 
-  // Overridden from views::View.
-  void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
-    node_data->SetName(accessible_name_);
-    node_data->role = ax::mojom::Role::kButton;
-  }
+void PowerTrayView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+  node_data->SetName(accessible_name_);
+  node_data->role = ax::mojom::Role::kButton;
+}
 
-  void UpdateStatus() {
-    UpdateImage();
-    SetVisible(PowerStatus::Get()->IsBatteryPresent());
-  }
+void PowerTrayView::OnPowerStatusChanged() {
+  UpdateStatus();
+}
 
- private:
-  void UpdateImage() {
-    const PowerStatus::BatteryImageInfo& info =
-        PowerStatus::Get()->GetBatteryImageInfo();
-    // Only change the image when the info changes. http://crbug.com/589348
-    if (info_ && info_->ApproximatelyEqual(info))
-      return;
-    image_view()->SetImage(PowerStatus::GetBatteryImage(
-        info, kTrayIconSize, SkColorSetA(kTrayIconColor, 0x4C),
-        kTrayIconColor));
-  }
+void PowerTrayView::UpdateStatus() {
+  UpdateImage();
+  SetVisible(PowerStatus::Get()->IsBatteryPresent());
+  accessible_name_ = PowerStatus::Get()->GetAccessibleNameString(true);
+}
 
-  base::string16 accessible_name_;
-  base::Optional<PowerStatus::BatteryImageInfo> info_;
-
-  DISALLOW_COPY_AND_ASSIGN(PowerTrayView);
-};
+void PowerTrayView::UpdateImage() {
+  const PowerStatus::BatteryImageInfo& info =
+      PowerStatus::Get()->GetBatteryImageInfo();
+  // Only change the image when the info changes. http://crbug.com/589348
+  if (info_ && info_->ApproximatelyEqual(info))
+    return;
+  info_ = info;
+  image_view()->SetImage(PowerStatus::GetBatteryImage(
+      info, kTrayIconSize, SkColorSetA(kTrayIconColor, 0x4C), kTrayIconColor));
+}
 
 }  // namespace tray
 
 TrayPower::TrayPower(SystemTray* system_tray)
     : SystemTrayItem(system_tray, UMA_POWER) {
-  PowerStatus::Get()->AddObserver(this);
 }
 
-TrayPower::~TrayPower() {
-  PowerStatus::Get()->RemoveObserver(this);
-}
+TrayPower::~TrayPower() = default;
 
 views::View* TrayPower::CreateTrayView(LoginStatus status) {
   // There may not be enough information when this is created about whether
@@ -95,7 +90,6 @@
   // necessary.
   CHECK(power_tray_ == nullptr);
   power_tray_ = new tray::PowerTrayView(this);
-  power_tray_->UpdateStatus();
   return power_tray_;
 }
 
@@ -109,9 +103,4 @@
   power_tray_ = nullptr;
 }
 
-void TrayPower::OnPowerStatusChanged() {
-  if (power_tray_)
-    power_tray_->UpdateStatus();
-}
-
 }  // namespace ash
diff --git a/ash/system/power/tray_power.h b/ash/system/power/tray_power.h
index 6bd9650..5bf8c100e 100644
--- a/ash/system/power/tray_power.h
+++ b/ash/system/power/tray_power.h
@@ -9,16 +9,38 @@
 
 #include "ash/system/power/power_status.h"
 #include "ash/system/tray/system_tray_item.h"
+#include "ash/system/tray/tray_item_view.h"
 #include "base/macros.h"
 
 namespace ash {
 
 namespace tray {
-class PowerTrayView;
-}
 
-class ASH_EXPORT TrayPower : public SystemTrayItem,
-                             public PowerStatus::Observer {
+class PowerTrayView : public TrayItemView, public PowerStatus::Observer {
+ public:
+  explicit PowerTrayView(SystemTrayItem* owner);
+
+  ~PowerTrayView() override;
+
+  // Overridden from views::View.
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+
+  // Overridden from PowerStatus::Observer.
+  void OnPowerStatusChanged() override;
+
+ private:
+  void UpdateStatus();
+  void UpdateImage();
+
+  base::string16 accessible_name_;
+  base::Optional<PowerStatus::BatteryImageInfo> info_;
+
+  DISALLOW_COPY_AND_ASSIGN(PowerTrayView);
+};
+
+}  // namespace tray
+
+class ASH_EXPORT TrayPower : public SystemTrayItem {
  public:
   explicit TrayPower(SystemTray* system_tray);
   ~TrayPower() override;
@@ -40,9 +62,6 @@
   views::View* CreateDefaultView(LoginStatus status) override;
   void OnTrayViewDestroyed() override;
 
-  // Overridden from PowerStatus::Observer.
-  void OnPowerStatusChanged() override;
-
   tray::PowerTrayView* power_tray_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(TrayPower);
diff --git a/ash/system/screen_security/screen_switch_check_controller.cc b/ash/system/screen_security/screen_switch_check_controller.cc
new file mode 100644
index 0000000..142d3247
--- /dev/null
+++ b/ash/system/screen_security/screen_switch_check_controller.cc
@@ -0,0 +1,112 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/screen_security/screen_switch_check_controller.h"
+
+#include "ash/shell.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "ash/system/tray/system_tray_notifier.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/views/controls/message_box_view.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/window/dialog_delegate.h"
+
+namespace ash {
+
+namespace {
+
+// Dialog that confirms the user wants to stop screen share/cast. Calls a
+// callback with the result.
+class CancelCastingDialog : public views::DialogDelegateView {
+ public:
+  CancelCastingDialog(base::OnceCallback<void(bool)> callback)
+      : callback_(std::move(callback)) {
+    AddChildView(new views::MessageBoxView(views::MessageBoxView::InitParams(
+        l10n_util::GetStringUTF16(IDS_DESKTOP_CASTING_ACTIVE_MESSAGE))));
+    SetLayoutManager(std::make_unique<views::FillLayout>());
+  }
+  ~CancelCastingDialog() override = default;
+
+  base::string16 GetWindowTitle() const override {
+    return l10n_util::GetStringUTF16(IDS_DESKTOP_CASTING_ACTIVE_TITLE);
+  }
+
+  int GetDialogButtons() const override {
+    return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
+  }
+
+  bool Cancel() override {
+    std::move(callback_).Run(false);
+    return true;
+  }
+
+  bool Accept() override {
+    // Stop screen sharing and capturing. When notified, all capture sessions or
+    // all share sessions will be stopped.
+    // Currently, the logic is in ScreenSecurityNotificationController.
+    Shell::Get()->system_tray_notifier()->NotifyScreenCaptureStop();
+    Shell::Get()->system_tray_notifier()->NotifyScreenShareStop();
+
+    std::move(callback_).Run(true);
+    return true;
+  }
+
+ private:
+  base::OnceCallback<void(bool)> callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(CancelCastingDialog);
+};
+
+}  // namespace
+
+ScreenSwitchCheckController::ScreenSwitchCheckController() {
+  Shell::Get()->system_tray_notifier()->AddScreenCaptureObserver(this);
+  Shell::Get()->system_tray_notifier()->AddScreenShareObserver(this);
+}
+
+ScreenSwitchCheckController::~ScreenSwitchCheckController() {
+  Shell::Get()->system_tray_notifier()->RemoveScreenShareObserver(this);
+  Shell::Get()->system_tray_notifier()->RemoveScreenCaptureObserver(this);
+}
+
+void ScreenSwitchCheckController::CanSwitchAwayFromActiveUser(
+    base::OnceCallback<void(bool)> callback) {
+  // If neither screen sharing nor capturing is going on we can immediately
+  // switch users.
+  if (!has_capture_ && !has_share_) {
+    std::move(callback).Run(true);
+    return;
+  }
+
+  views::DialogDelegate::CreateDialogWidget(
+      new CancelCastingDialog(std::move(callback)),
+      Shell::GetPrimaryRootWindow(), nullptr)
+      ->Show();
+}
+
+void ScreenSwitchCheckController::OnScreenCaptureStart(
+    const base::Closure& stop_callback,
+    const base::string16& screen_capture_status) {
+  has_capture_ = true;
+}
+
+void ScreenSwitchCheckController::OnScreenCaptureStop() {
+  // Multiple screen capture sessions can exist, but they are stopped at once
+  // for simplicity.
+  has_capture_ = false;
+}
+
+void ScreenSwitchCheckController::OnScreenShareStart(
+    const base::Closure& stop_callback,
+    const base::string16& helper_name) {
+  has_share_ = true;
+}
+
+void ScreenSwitchCheckController::OnScreenShareStop() {
+  // Multiple screen share sessions can exist, but they are stopped at once for
+  // simplicity.
+  has_share_ = false;
+}
+
+}  // namespace ash
diff --git a/ash/system/screen_security/screen_switch_check_controller.h b/ash/system/screen_security/screen_switch_check_controller.h
new file mode 100644
index 0000000..d27db2d
--- /dev/null
+++ b/ash/system/screen_security/screen_switch_check_controller.h
@@ -0,0 +1,46 @@
+// Copyright 2018 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_SYSTEM_SCREEN_SECURITY_SCREEN_SWITCH_CHECK_CONTROLLER_H_
+#define ASH_SYSTEM_SCREEN_SECURITY_SCREEN_SWITCH_CHECK_CONTROLLER_H_
+
+#include "ash/system/screen_security/screen_capture_observer.h"
+#include "ash/system/screen_security/screen_share_observer.h"
+
+namespace ash {
+
+// Controller of a dialog that confirms the user wants to stop screen share/cast
+// on user profile switching.
+class ScreenSwitchCheckController : public ScreenCaptureObserver,
+                                    public ScreenShareObserver {
+ public:
+  ScreenSwitchCheckController();
+  ~ScreenSwitchCheckController() override;
+
+  // Determines if it's ok to switch away from the currently active user. Screen
+  // casting may block this (or at least throw up a confirmation dialog). Calls
+  // |callback| with the result.
+  void CanSwitchAwayFromActiveUser(base::OnceCallback<void(bool)> callback);
+
+ private:
+  // ScreenCaptureObserver:
+  void OnScreenCaptureStart(
+      const base::Closure& stop_callback,
+      const base::string16& screen_capture_status) override;
+  void OnScreenCaptureStop() override;
+
+  // ScreenShareObserver:
+  void OnScreenShareStart(const base::Closure& stop_callback,
+                          const base::string16& helper_name) override;
+  void OnScreenShareStop() override;
+
+  bool has_capture_ = false;
+  bool has_share_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(ScreenSwitchCheckController);
+};
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_SCREEN_SECURITY_SCREEN_SWITCH_CHECK_CONTROLLER_H_
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc
index 139ff5e..41729b5 100644
--- a/ash/system/tray/system_tray.cc
+++ b/ash/system/tray/system_tray.cc
@@ -79,11 +79,8 @@
 #include "ui/native_theme/native_theme.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/label.h"
-#include "ui/views/controls/message_box_view.h"
-#include "ui/views/layout/fill_layout.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
-#include "ui/views/window/dialog_delegate.h"
 #include "ui/wm/core/window_util.h"
 #include "ui/wm/public/activation_change_observer.h"
 #include "ui/wm/public/activation_client.h"
@@ -94,49 +91,6 @@
 
 namespace {
 
-// Dialog that confirms the user wants to stop screen share/cast. Calls a
-// callback with the result.
-class CancelCastingDialog : public views::DialogDelegateView {
- public:
-  explicit CancelCastingDialog(base::OnceCallback<void(bool)> callback)
-      : callback_(std::move(callback)) {
-    AddChildView(new views::MessageBoxView(views::MessageBoxView::InitParams(
-        l10n_util::GetStringUTF16(IDS_DESKTOP_CASTING_ACTIVE_MESSAGE))));
-    SetLayoutManager(std::make_unique<views::FillLayout>());
-  }
-  ~CancelCastingDialog() override = default;
-
-  base::string16 GetWindowTitle() const override {
-    return l10n_util::GetStringUTF16(IDS_DESKTOP_CASTING_ACTIVE_TITLE);
-  }
-
-  int GetDialogButtons() const override {
-    return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
-  }
-
-  bool Cancel() override {
-    std::move(callback_).Run(false);
-    return true;
-  }
-
-  bool Accept() override {
-    // Stop screen sharing and capturing.
-    SystemTray* system_tray = Shell::Get()->GetPrimarySystemTray();
-    if (system_tray->GetScreenShareItem()->is_started())
-      system_tray->GetScreenShareItem()->Stop();
-    if (system_tray->GetScreenCaptureItem()->is_started())
-      system_tray->GetScreenCaptureItem()->Stop();
-
-    std::move(callback_).Run(true);
-    return true;
-  }
-
- private:
-  base::OnceCallback<void(bool)> callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(CancelCastingDialog);
-};
-
 // A tray item that just reserves space in the tray.
 class PaddingTrayItem : public SystemTrayItem {
  public:
@@ -276,10 +230,8 @@
   AddTrayItem(base::WrapUnique(tray_bluetooth_));
   tray_cast_ = new TrayCast(this);
   AddTrayItem(base::WrapUnique(tray_cast_));
-  screen_capture_tray_item_ = new ScreenCaptureTrayItem(this);
-  AddTrayItem(base::WrapUnique(screen_capture_tray_item_));
-  screen_share_tray_item_ = new ScreenShareTrayItem(this);
-  AddTrayItem(base::WrapUnique(screen_share_tray_item_));
+  AddTrayItem(std::make_unique<ScreenCaptureTrayItem>(this));
+  AddTrayItem(std::make_unique<ScreenShareTrayItem>(this));
   AddTrayItem(std::make_unique<MultiProfileMediaTrayItem>(this));
   tray_audio_ = new TrayAudio(this);
   AddTrayItem(base::WrapUnique(tray_audio_));
@@ -435,22 +387,6 @@
   last_button_clicked_.reset();
 }
 
-void SystemTray::CanSwitchAwayFromActiveUser(
-    base::OnceCallback<void(bool)> callback) {
-  // If neither screen sharing nor capturing is going on we can immediately
-  // switch users.
-  if (!GetScreenShareItem()->is_started() &&
-      !GetScreenCaptureItem()->is_started()) {
-    std::move(callback).Run(true);
-    return;
-  }
-
-  views::DialogDelegate::CreateDialogWidget(
-      new CancelCastingDialog(std::move(callback)),
-      Shell::GetPrimaryRootWindow(), nullptr)
-      ->Show();
-}
-
 // Private methods.
 
 bool SystemTray::HasSystemTrayType(SystemTrayView::SystemTrayType type) {
diff --git a/ash/system/tray/system_tray.h b/ash/system/tray/system_tray.h
index d545436e..73a2ff98 100644
--- a/ash/system/tray/system_tray.h
+++ b/ash/system/tray/system_tray.h
@@ -135,11 +135,6 @@
   // Returns TrayIME object if present or null otherwise.
   TrayIME* GetTrayIME() const;
 
-  // Determines if it's ok to switch away from the currently active user. Screen
-  // casting may block this (or at least throw up a confirmation dialog). Calls
-  // |callback| with the result.
-  void CanSwitchAwayFromActiveUser(base::OnceCallback<void(bool)> callback);
-
   // TrayBackgroundView:
   void UpdateAfterShelfAlignmentChange() override;
   void AnchorUpdated() override;
@@ -164,9 +159,6 @@
   // TimeToClickRecorder::Delegate:
   void RecordTimeToClick() override;
 
-  ScreenTrayItem* GetScreenShareItem() { return screen_share_tray_item_; }
-  ScreenTrayItem* GetScreenCaptureItem() { return screen_capture_tray_item_; }
-
   // Activates the system tray bubble.
   void ActivateBubble();
 
@@ -251,10 +243,6 @@
   TrayUpdate* tray_update_ = nullptr;
   TrayNightLight* tray_night_light_ = nullptr;
 
-  // A reference to the Screen share and capture item.
-  ScreenTrayItem* screen_capture_tray_item_ = nullptr;  // not owned
-  ScreenTrayItem* screen_share_tray_item_ = nullptr;    // not owned
-
   DISALLOW_COPY_AND_ASSIGN(SystemTray);
 };
 
diff --git a/ash/system/tray/tray_item_view.cc b/ash/system/tray/tray_item_view.cc
index 393e3e68..7bb70eb 100644
--- a/ash/system/tray/tray_item_view.cc
+++ b/ash/system/tray/tray_item_view.cc
@@ -85,7 +85,7 @@
   gfx::Size size = rect.size();
   if (!animation_.get() || !animation_->is_animating())
     return size;
-  if (owner()->system_tray()->shelf()->IsHorizontalAlignment()) {
+  if (owner() && owner()->system_tray()->shelf()->IsHorizontalAlignment()) {
     size.set_width(std::max(
         1, static_cast<int>(size.width() * animation_->GetCurrentValue())));
   } else {
@@ -105,7 +105,7 @@
 
 void TrayItemView::AnimationProgressed(const gfx::Animation* animation) {
   gfx::Transform transform;
-  if (owner()->system_tray()->shelf()->IsHorizontalAlignment()) {
+  if (owner() && owner()->system_tray()->shelf()->IsHorizontalAlignment()) {
     transform.Translate(0, animation->CurrentValueBetween(
                                static_cast<double>(height()) / 2, 0.));
   } else {
diff --git a/ash/system/unified/unified_system_tray.cc b/ash/system/unified/unified_system_tray.cc
index 9ce5cb1..93c260b 100644
--- a/ash/system/unified/unified_system_tray.cc
+++ b/ash/system/unified/unified_system_tray.cc
@@ -8,6 +8,7 @@
 #include "ash/system/date/date_view.h"
 #include "ash/system/message_center/ash_popup_alignment_delegate.h"
 #include "ash/system/model/system_tray_model.h"
+#include "ash/system/power/tray_power.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/tray_container.h"
@@ -100,9 +101,12 @@
     : TrayBackgroundView(shelf),
       ui_delegate_(std::make_unique<UiDelegate>(this)),
       model_(std::make_unique<UnifiedSystemTrayModel>()) {
-  tray_container()->AddChildView(
+  tray_container()->AddChildView(new tray::PowerTrayView(nullptr));
+  TrayItemView* time_item = new TrayItemView(nullptr);
+  time_item->AddChildView(
       new tray::TimeView(tray::TimeView::ClockLayout::HORIZONTAL_CLOCK,
                          Shell::Get()->system_tray_model()->clock()));
+  tray_container()->AddChildView(time_item);
   SetInkDropMode(InkDropMode::ON);
   SetVisible(true);
 }
diff --git a/ash/system/unified/unified_system_tray_controller.cc b/ash/system/unified/unified_system_tray_controller.cc
index 78d8b61f..4716d6c1 100644
--- a/ash/system/unified/unified_system_tray_controller.cc
+++ b/ash/system/unified/unified_system_tray_controller.cc
@@ -29,6 +29,7 @@
 #include "ash/system/unified/unified_system_tray_model.h"
 #include "ash/system/unified/unified_system_tray_view.h"
 #include "ash/wm/lock_state_controller.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/numerics/ranges.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/session_manager_client.h"
@@ -100,6 +101,9 @@
 }
 
 void UnifiedSystemTrayController::ToggleExpanded() {
+  UMA_HISTOGRAM_ENUMERATION("ChromeOS.SystemTray.ToggleExpanded",
+                            TOGGLE_EXPANDED_TYPE_BY_BUTTON,
+                            TOGGLE_EXPANDED_TYPE_COUNT);
   if (animation_->IsShowing())
     animation_->Hide();
   else
@@ -117,8 +121,15 @@
 }
 
 void UnifiedSystemTrayController::EndDrag(const gfx::Point& location) {
+  bool expanded = GetDragExpandedAmount(location) > 0.5;
+  if (was_expanded_ != expanded) {
+    UMA_HISTOGRAM_ENUMERATION("ChromeOS.SystemTray.ToggleExpanded",
+                              TOGGLE_EXPANDED_TYPE_BY_GESTURE,
+                              TOGGLE_EXPANDED_TYPE_COUNT);
+  }
+
   // If dragging is finished, animate to closer state.
-  if (GetDragExpandedAmount(location) > 0.5) {
+  if (expanded) {
     animation_->Show();
   } else {
     // To animate to hidden state, first set SlideAnimation::IsShowing() to
diff --git a/ash/system/unified/unified_system_tray_controller.h b/ash/system/unified/unified_system_tray_controller.h
index 52e11cf..f540518 100644
--- a/ash/system/unified/unified_system_tray_controller.h
+++ b/ash/system/unified/unified_system_tray_controller.h
@@ -74,6 +74,14 @@
   UnifiedSystemTrayModel* model() { return model_; }
 
  private:
+  // How the expanded state is toggled. The enum is used to back an UMA
+  // histogram and should be treated as append-only.
+  enum ToggleExpandedType {
+    TOGGLE_EXPANDED_TYPE_BY_BUTTON = 0,
+    TOGGLE_EXPANDED_TYPE_BY_GESTURE,
+    TOGGLE_EXPANDED_TYPE_COUNT
+  };
+
   // Initialize feature pod controllers and their views.
   // If you want to add a new feature pod item, you have to add here.
   void InitFeaturePods();
diff --git a/base/sys_info_mac.mm b/base/sys_info_mac.mm
index 8ba29cc..89bebb81 100644
--- a/base/sys_info_mac.mm
+++ b/base/sys_info_mac.mm
@@ -57,35 +57,14 @@
 void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
                                             int32_t* minor_version,
                                             int32_t* bugfix_version) {
-  NSProcessInfo* processInfo = [NSProcessInfo processInfo];
-  // We should try to avoid using Gestalt here because it has been observed to
-  // spin up threads among other things. Using an availability check here would
-  // prevent us from using the private API in 10.9.2. So use a
-  // respondsToSelector check here instead and silence the warning.
-  if ([processInfo respondsToSelector:@selector(operatingSystemVersion)]) {
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability"
-    NSOperatingSystemVersion version = [processInfo operatingSystemVersion];
-#pragma clang diagnostic pop
+  if (@available(macOS 10.10, *)) {
+    NSOperatingSystemVersion version =
+        [[NSProcessInfo processInfo] operatingSystemVersion];
     *major_version = version.majorVersion;
     *minor_version = version.minorVersion;
     *bugfix_version = version.patchVersion;
   } else {
-    // -[NSProcessInfo operatingSystemVersion] is documented available in 10.10.
-    // It's also available via a private API since 10.9.2. For the remaining
-    // cases in 10.9, rely on ::Gestalt(..). Since this code is only needed for
-    // 10.9.0 and 10.9.1 and uses the recommended replacement thereafter,
-    // suppress the warning for this fallback case.
-    DCHECK(base::mac::IsOS10_9());
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-    Gestalt(gestaltSystemVersionMajor,
-            reinterpret_cast<SInt32*>(major_version));
-    Gestalt(gestaltSystemVersionMinor,
-            reinterpret_cast<SInt32*>(minor_version));
-    Gestalt(gestaltSystemVersionBugFix,
-            reinterpret_cast<SInt32*>(bugfix_version));
-#pragma clang diagnostic pop
+    NOTREACHED();
   }
 }
 
diff --git a/chrome/VERSION b/chrome/VERSION
index a8f5a7e..209f43ae 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=68
 MINOR=0
-BUILD=3426
+BUILD=3427
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 527b081..227ac112 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -818,6 +818,14 @@
                         && getFullscreenManager().getPersistentFullscreenMode()) {
                     return;
                 }
+
+                Layout activeLayout = mLayoutManager.getActiveLayout();
+                if (activeLayout instanceof StackLayout) {
+                    if (!activeLayout.isHiding()) {
+                        RecordUserAction.record("MobileToolbarStackViewButtonInStackView");
+                    }
+                }
+
                 toggleOverview();
             };
             OnClickListener newTabClickHandler = v -> {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
index 380290f..072338f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
@@ -162,6 +162,9 @@
     /** Which model (normal or incognito) was active when StackLayout was shown. */
     private int mModelIndexWhenOpened;
 
+    /** ID of the tab that was active when this layout was shown. */
+    private int mCurrentTabIdWhenOpened;
+
     /**
      * Temporarily stores the index of the selected tab stack. This is used to set the currently
      * selected stack in TabModelSelector once the stack-switching animation finishes.
@@ -713,6 +716,7 @@
             RecordUserAction.record("MobileToolbarShowStackView");
 
             mModelIndexWhenOpened = mTabModelSelector.getCurrentModelIndex();
+            mCurrentTabIdWhenOpened = mTabModelSelector.getCurrentTabId();
         }
         mIsActiveLayout = true;
 
@@ -1241,6 +1245,10 @@
         // button on the toolbar to re-open it while we're still in the process of hiding the tab
         // switcher, we don't skip the logging.
         mIsActiveLayout = false;
+
+        if (mCurrentTabIdWhenOpened == nextTabId) {
+            RecordUserAction.record("MobileTabReturnedToCurrentTab");
+        }
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
index 0c923d1c..7b480bbc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
@@ -271,7 +271,7 @@
     }
 
     @VisibleForTesting
-    static ArrayList<String> getSpecializedHandlersWithFilter(
+    public static ArrayList<String> getSpecializedHandlersWithFilter(
             List<ResolveInfo> infos, String filterPackageName) {
         ArrayList<String> result = new ArrayList<>();
         if (infos == null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
index 3dc2863..57e7bb0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
@@ -4,6 +4,11 @@
 
 package org.chromium.chrome.browser.externalnav;
 
+import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.EXTRA_BROWSER_LAUNCH_SOURCE;
+import static org.chromium.chrome.browser.webapps.WebappActivity.ACTIVITY_TYPE_OTHER;
+import static org.chromium.chrome.browser.webapps.WebappActivity.ACTIVITY_TYPE_TWA;
+import static org.chromium.chrome.browser.webapps.WebappActivity.ACTIVITY_TYPE_WEBAPK;
+
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -35,6 +40,7 @@
 import org.chromium.ui.base.PageTransition;
 
 import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.HashSet;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
@@ -564,6 +570,14 @@
                 intent.setPackage(targetWebApkPackageName);
             }
 
+            // http://crbug.com/831806 : Stay in the CCT if the CCT is opened by WebAPK and the url
+            // is within the WebAPK scope.
+            if (shouldStayInWebappCCT(params, resolvingInfos)) {
+                if (DEBUG)
+                    Log.i(TAG, "NO_OVERRIDE: Navigation in CCT within scope of parent webapp.");
+                return OverrideUrlLoadingResult.NO_OVERRIDE;
+            }
+
             if (mDelegate.startActivityIfNeeded(intent, shouldProxyForInstantApps)) {
                 if (DEBUG) Log.i(TAG, "OVERRIDE_WITH_EXTERNAL_INTENT: startActivityIfNeeded");
                 return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT;
@@ -707,4 +721,33 @@
         }
         return null;
     }
+
+    // Returns whether a navigation in a CustomTabActivity opened from a WebAPK/TWA should stay
+    // within the CustomTabActivity. Returns false if the navigation does not occur within a
+    // CustomTabActivity or the CustomTabActivity was not opened from a WebAPK/TWA.
+    private boolean shouldStayInWebappCCT(
+            ExternalNavigationParams params, List<ResolveInfo> handlers) {
+        Tab tab = params.getTab();
+        if (tab == null || !tab.isCurrentlyACustomTab() || tab.getActivity() == null) {
+            return false;
+        }
+
+        int launchSource = IntentUtils.safeGetIntExtra(
+                tab.getActivity().getIntent(), EXTRA_BROWSER_LAUNCH_SOURCE, ACTIVITY_TYPE_OTHER);
+        if (launchSource != ACTIVITY_TYPE_WEBAPK && launchSource != ACTIVITY_TYPE_TWA) return false;
+
+        String appId = IntentUtils.safeGetStringExtra(
+                tab.getActivity().getIntent(), Browser.EXTRA_APPLICATION_ID);
+        if (appId == null) return false;
+
+        Intent intent;
+        try {
+            intent = Intent.parseUri(params.getUrl(), Intent.URI_INTENT_SCHEME);
+        } catch (URISyntaxException ex) {
+            return false;
+        }
+        return ExternalNavigationDelegateImpl.getSpecializedHandlersWithFilter(handlers, appId)
+                       .size()
+                > 0;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index 108a2c1..f64b9b30 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -55,12 +55,15 @@
 import org.chromium.chrome.browser.compositor.Invalidator;
 import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost;
 import org.chromium.chrome.browser.device.DeviceClassManager;
+import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.fullscreen.BrowserStateBrowserControlsVisibilityDelegate;
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
 import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.omnibox.LocationBar;
 import org.chromium.chrome.browser.omnibox.LocationBarPhone;
 import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
+import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomizations;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
 import org.chromium.chrome.browser.util.ColorUtils;
@@ -71,6 +74,7 @@
 import org.chromium.chrome.browser.widget.animation.CancelAwareAnimatorListener;
 import org.chromium.chrome.browser.widget.newtab.NewTabButton;
 import org.chromium.chrome.browser.widget.textbubble.TextBubble;
+import org.chromium.components.feature_engagement.EventConstants;
 import org.chromium.ui.base.LocalizationUtils;
 import org.chromium.ui.interpolators.BakedBezierInterpolator;
 
@@ -581,6 +585,11 @@
             }
         } else if (mHomeButton != null && mHomeButton == v) {
             openHomepage();
+            if (isNativeLibraryReady()
+                    && PartnerBrowserCustomizations.isHomepageProviderAvailableAndEnabled()) {
+                TrackerFactory.getTrackerForProfile(Profile.getLastUsedProfile())
+                        .notifyEvent(EventConstants.PARTNER_HOME_PAGE_BUTTON_PRESSED);
+            }
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
index 6bb1274..b495d3a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -927,7 +927,7 @@
 
     @Override
     protected TabDelegate createTabDelegate(boolean incognito) {
-        return new WebappTabDelegate(incognito, getActivityType(), mWebappInfo.apkPackageName());
+        return new WebappTabDelegate(incognito, getActivityType(), getNativeClientPackageName());
     }
 
     // We're temporarily disable CS on webapp since there are some issues. (http://crbug.com/471950)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappTabDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappTabDelegate.java
index 13994b3..15d8bc1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappTabDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappTabDelegate.java
@@ -4,6 +4,8 @@
 package org.chromium.chrome.browser.webapps;
 
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.net.Uri;
 import android.os.StrictMode;
 import android.provider.Browser;
@@ -22,6 +24,7 @@
 import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
 
 import java.net.URISyntaxException;
+import java.util.List;
 
 /**
  * Asynchronously creates Tabs for navigation originating from an installed PWA.
@@ -74,8 +77,25 @@
         // See http://crbug.com/613977 for more context.
         StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
+            List<ResolveInfo> handlers =
+                    ContextUtils.getApplicationContext().getPackageManager().queryIntentActivities(
+                            intent, PackageManager.GET_RESOLVED_FILTER);
+
+            boolean foundSpecializedHandler = false;
+
+            for (String result : ExternalNavigationDelegateImpl.getSpecializedHandlersWithFilter(
+                         handlers, null)) {
+                if (result.equals(mApkPackageName)) {
+                    // Current webapk matches, don't intercept so that we can launch a cct. See
+                    // http://crbug.com/831806 for more context.
+                    return false;
+                } else {
+                    foundSpecializedHandler = true;
+                }
+            }
+
             // Launch a native app iff there is a specialized handler for a given URL.
-            if (ExternalNavigationDelegateImpl.isPackageSpecializedHandler(null, intent)) {
+            if (foundSpecializedHandler) {
                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 ContextUtils.getApplicationContext().startActivity(intent);
                 return true;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/FullscreenActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/FullscreenActivityTest.java
index 0560b22..d2287e8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/FullscreenActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/FullscreenActivityTest.java
@@ -19,7 +19,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.ApplicationStatus;
 import org.chromium.base.Callback;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
@@ -69,24 +68,6 @@
     }
 
     /**
-     * Waits for an Activity of the given class to be started and for it to have a Tab.
-     * @return The Activity.
-     */
-    @SuppressWarnings("unchecked")
-    private static <T extends ChromeActivity> T waitForActivity(final Class<T> activityClass) {
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                Activity lastActivity = ApplicationStatus.getLastTrackedFocusedActivity();
-                if (lastActivity.getClass() != activityClass) return false;
-
-                return ((ChromeActivity) lastActivity).getActivityTab() != null;
-            }
-        });
-        return (T) ApplicationStatus.getLastTrackedFocusedActivity();
-    }
-
-    /**
      * Tests that the window system visibility has flags set that indicate it is fullscreen. This is
      * useful because there is a slight discrepancy between when the webpage thinks it is fullscreen
      * and when the window thinks it is fullscreen that can lead to a race condition during tests.
@@ -110,7 +91,8 @@
         // Trigger requestFullscreen() via a click on a button.
         Assert.assertTrue(DOMUtils.clickNode(webContents, "fullscreen"));
 
-        final FullscreenActivity fullscreenActivity = waitForActivity(FullscreenActivity.class);
+        final FullscreenActivity fullscreenActivity =
+                ChromeActivityTestRule.waitFor(FullscreenActivity.class);
 
         CriteriaHelper.pollInstrumentationThread(new Criteria() {
             @Override
@@ -143,7 +125,7 @@
 
         exit.onResult(fullscreenActivity);
 
-        ChromeTabbedActivity activity = waitForActivity(ChromeTabbedActivity.class);
+        ChromeTabbedActivity activity = ChromeActivityTestRule.waitFor(ChromeTabbedActivity.class);
 
         // Ensure we haven't started a new ChromeTabbedActivity, https://crbug.com/729805,
         // https://crbug.com/729932.
@@ -187,7 +169,7 @@
         FullscreenActivity fullscreenActivity = enterFullscreen();
         DOMUtils.exitFullscreen(fullscreenActivity.getCurrentWebContents());
 
-        waitForActivity(ChromeTabbedActivity.class);
+        ChromeActivityTestRule.waitFor(ChromeTabbedActivity.class);
 
         Assert.assertEquals(old, mActivity.getTabsView().getSystemUiVisibility());
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
index a134f7a66..f839de6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
@@ -23,12 +23,16 @@
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.DeferredStartupHandler;
 import org.chromium.chrome.browser.ShortcutHelper;
+import org.chromium.chrome.browser.customtabs.CustomTabActivity;
+import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
+import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.content.browser.test.NativeLibraryTestRule;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.content.browser.test.util.JavaScriptUtils;
 import org.chromium.content.common.ContentSwitches;
 import org.chromium.net.test.EmbeddedTestServerRule;
 import org.chromium.webapk.lib.client.WebApkValidator;
@@ -152,6 +156,53 @@
     }
 
     /**
+     * Test launching a WebAPK. Test that open a url within scope through window.open() will open a
+     * CCT.
+     */
+    @Test
+    @LargeTest
+    @Feature({"WebApk"})
+    public void testLaunchAndOpenNewWindowInOrigin() throws Exception {
+        String pwaRocksUrl = getUrlForHost("pwa.rocks");
+        startWebApkActivity("org.chromium.webapk.http", pwaRocksUrl);
+        waitUntilSplashscreenHides();
+
+        WebappActivityTestRule.jsWindowOpen(mActivityTestRule.getActivity(), pwaRocksUrl);
+
+        CustomTabActivity customTabActivity =
+                ChromeActivityTestRule.waitFor(CustomTabActivity.class);
+        ChromeTabUtils.waitForTabPageLoaded(customTabActivity.getActivityTab(), pwaRocksUrl);
+        Assert.assertTrue(
+                "Sending to external handlers needs to be enabled for redirect back (e.g. OAuth).",
+                IntentUtils.safeGetBooleanExtra(customTabActivity.getIntent(),
+                        CustomTabIntentDataProvider.EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER, false));
+    }
+
+    /**
+     * Test launching a WebAPK. Test that open a url off scope through window.open() will open a
+     * CCT, and in scope urls will stay in the CCT.
+     */
+    @Test
+    @LargeTest
+    @Feature({"WebApk"})
+    public void testLaunchAndNavigationInNewWindowOffandInOrigin() throws Exception {
+        String pwaRocksUrl = getUrlForHost("pwa.rocks");
+        String googleUrl = getUrlForHost("www.google.com");
+        startWebApkActivity("org.chromium.webapk.http", pwaRocksUrl);
+        waitUntilSplashscreenHides();
+
+        WebappActivityTestRule.jsWindowOpen(mActivityTestRule.getActivity(), googleUrl);
+        CustomTabActivity customTabActivity =
+                ChromeActivityTestRule.waitFor(CustomTabActivity.class);
+        ChromeTabUtils.waitForTabPageLoaded(customTabActivity.getActivityTab(), googleUrl);
+
+        JavaScriptUtils.executeJavaScriptAndWaitForResult(
+                customTabActivity.getActivityTab().getWebContents(),
+                String.format("window.location.href='%s'", pwaRocksUrl));
+        ChromeTabUtils.waitForTabPageLoaded(customTabActivity.getActivityTab(), pwaRocksUrl);
+    }
+
+    /**
      * Test that on first launch:
      * - the "WebApk.LaunchInterval" histogram is not recorded (because there is no prevous launch
      *   to compute the interval from).
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java
index 1905fb0d..0bce361 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java
@@ -25,6 +25,8 @@
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.content.browser.test.util.DOMUtils;
+import org.chromium.content.browser.test.util.JavaScriptUtils;
 import org.chromium.net.test.EmbeddedTestServer;
 import org.chromium.net.test.EmbeddedTestServerRule;
 
@@ -178,6 +180,25 @@
     }
 
     /**
+     * Executing window.open() through a click on a link, as it needs user gesture to avoid Chrome
+     * blocking it as a popup.
+     */
+    static public void jsWindowOpen(ChromeActivity activity, String url) throws Exception {
+        String injectedHtml = String.format("var aTag = document.createElement('testId');"
+                        + "aTag.id = 'testId';"
+                        + "aTag.innerHTML = 'Click Me!';"
+                        + "aTag.onclick = function() {"
+                        + "  window.open('%s');"
+                        + "  return false;"
+                        + "};"
+                        + "document.body.insertAdjacentElement('afterbegin', aTag);",
+                url);
+        JavaScriptUtils.executeJavaScriptAndWaitForResult(
+                activity.getActivityTab().getWebContents(), injectedHtml);
+        DOMUtils.clickNode(activity.getActivityTab().getWebContents(), "testId");
+    }
+
+    /**
      * Waits until any loads in progress of the activity under test have completed.
      */
     protected void waitUntilIdle() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
index 8239370..c58b9af 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
@@ -8,7 +8,6 @@
 import static org.chromium.base.ApplicationState.HAS_PAUSED_ACTIVITIES;
 import static org.chromium.base.ApplicationState.HAS_STOPPED_ACTIVITIES;
 
-import android.app.Activity;
 import android.content.Intent;
 import android.graphics.Color;
 import android.support.test.InstrumentationRegistry;
@@ -31,7 +30,6 @@
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.blink_public.platform.WebDisplayMode;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.ShortcutHelper;
@@ -40,6 +38,7 @@
 import org.chromium.chrome.browser.firstrun.FirstRunStatus;
 import org.chromium.chrome.browser.tab.InterceptNavigationDelegateImpl;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.chrome.test.util.MenuUtils;
@@ -121,7 +120,7 @@
 
     /**
      * Test that navigating a TWA outside of the TWA scope by tapping a regular link:
-     * - Expects the CCT toolbar to be shown.
+     * - Expects the Minimal UI toolbar to be shown.
      * - Uses the TWA theme colour in the Minimal UI toolbar.
      */
     @Test
@@ -132,8 +131,7 @@
                 ShortcutHelper.EXTRA_THEME_COLOR, (long) Color.CYAN);
         mActivityTestRule.addTwaExtrasToIntent(launchIntent);
         String url = WebappTestPage.getServiceWorkerUrl(mActivityTestRule.getTestServer());
-        CommandLine commandLine = CommandLine.getInstance();
-        commandLine.appendSwitchWithValue(
+        CommandLine.getInstance().appendSwitchWithValue(
                 ChromeSwitches.DISABLE_DIGITAL_ASSET_LINK_VERIFICATION, url);
         mActivityTestRule.startWebappActivity(launchIntent.putExtra(ShortcutHelper.EXTRA_URL, url));
         mActivityTestRule.waitUntilSplashscreenHides();
@@ -147,9 +145,34 @@
     }
 
     /**
+     * Test that navigating outside of the webapp scope as a result of submitting a form with method
+     * "POST":
+     * - Shows a CCT-like webapp toolbar.
+     * - Preserves the theme color specified in the launch intent.
+     */
+    @Test
+    @SmallTest
+    @Feature({"Webapps"})
+    @RetryOnFailure
+    public void testFormSubmitOffOrigin() throws Exception {
+        Intent launchIntent = mActivityTestRule.createIntent().putExtra(
+                ShortcutHelper.EXTRA_THEME_COLOR, (long) Color.CYAN);
+        mActivityTestRule.addTwaExtrasToIntent(launchIntent);
+        WebappActivity activity = runWebappActivityAndWaitForIdleWithUrl(launchIntent,
+                mActivityTestRule.getTestServer().getURL("/chrome/test/data/android/form.html"));
+
+        mActivityTestRule.runJavaScriptCodeInCurrentTab(String.format(
+                "document.getElementById('form').setAttribute('action', '%s')", offOriginUrl()));
+        clickNodeWithId("post_button");
+
+        ChromeTabUtils.waitForTabPageLoaded(activity.getActivityTab(), offOriginUrl());
+        Assert.assertEquals(Color.CYAN, activity.getToolbarManager().getPrimaryColor());
+    }
+
+    /**
      * Test that navigating outside of the webapp scope by tapping a link with target="_blank":
      * - Launches a CCT.
-     * - The CCT toolbar does not use the webapp theme colour.
+     * - The Minimal UI toolbar does not use the webapp theme colour.
      */
     @Test
     @SmallTest
@@ -159,7 +182,7 @@
         runWebappActivityAndWaitForIdle(mActivityTestRule.createIntent().putExtra(
                 ShortcutHelper.EXTRA_THEME_COLOR, (long) Color.CYAN));
         addAnchorAndClick(offOriginUrl(), "_blank");
-        CustomTabActivity customTab = waitFor(CustomTabActivity.class);
+        CustomTabActivity customTab = ChromeActivityTestRule.waitFor(CustomTabActivity.class);
         ChromeTabUtils.waitForTabPageLoaded(customTab.getActivityTab(), offOriginUrl());
 
         Assert.assertEquals(
@@ -180,7 +203,7 @@
         runWebappActivityAndWaitForIdle(mActivityTestRule.createIntent().putExtra(
                 ShortcutHelper.EXTRA_THEME_COLOR, (long) Color.CYAN));
         addAnchorAndClick(inScopeUrl, "_blank");
-        CustomTabActivity customTab = waitFor(CustomTabActivity.class);
+        CustomTabActivity customTab = ChromeActivityTestRule.waitFor(CustomTabActivity.class);
         ChromeTabUtils.waitForTabPageLoaded(customTab.getActivityTab(), inScopeUrl);
         Assert.assertTrue(
                 mActivityTestRule.runJavaScriptCodeInCurrentTab("document.body.textContent")
@@ -199,21 +222,9 @@
     public void testWindowOpenInCct() throws Exception {
         runWebappActivityAndWaitForIdle(mActivityTestRule.createIntent().putExtra(
                 ShortcutHelper.EXTRA_THEME_COLOR, (long) Color.CYAN));
-        // Executing window.open() through a click on a link,
-        // as it needs user gesture to avoid Chrome blocking it as a popup.
-        mActivityTestRule.runJavaScriptCodeInCurrentTab(
-                String.format("var aTag = document.createElement('testId');"
-                                + "aTag.id = 'testId';"
-                                + "aTag.innerHTML = 'Click Me!';"
-                                + "aTag.onclick = function() {"
-                                + "  window.open('%s');"
-                                + "  return false;"
-                                + "};"
-                                + "document.body.appendChild(aTag);",
-                        offOriginUrl()));
-        clickNodeWithId("testId");
 
-        CustomTabActivity customTab = waitFor(CustomTabActivity.class);
+        WebappActivityTestRule.jsWindowOpen(mActivityTestRule.getActivity(), offOriginUrl());
+        CustomTabActivity customTab = ChromeActivityTestRule.waitFor(CustomTabActivity.class);
         ChromeTabUtils.waitForTabPageLoaded(customTab.getActivityTab(), offOriginUrl());
         Assert.assertEquals(
                 getDefaultPrimaryColor(), customTab.getToolbarManager().getPrimaryColor());
@@ -254,7 +265,8 @@
                 mActivityTestRule.getActivity().getActivityTab(), "myTestAnchorId",
                 R.id.contextmenu_open_in_chrome);
 
-        ChromeTabbedActivity tabbedChrome = waitFor(ChromeTabbedActivity.class);
+        ChromeTabbedActivity tabbedChrome =
+                ChromeActivityTestRule.waitFor(ChromeTabbedActivity.class);
         ChromeTabUtils.waitForTabPageLoaded(tabbedChrome.getActivityTab(), offOriginUrl());
     }
 
@@ -270,7 +282,8 @@
         MenuUtils.invokeCustomMenuActionSync(
                 InstrumentationRegistry.getInstrumentation(), activity, R.id.open_in_browser_id);
 
-        ChromeTabbedActivity tabbedChrome = waitFor(ChromeTabbedActivity.class);
+        ChromeTabbedActivity tabbedChrome =
+                ChromeActivityTestRule.waitFor(ChromeTabbedActivity.class);
         ChromeTabUtils.waitForTabPageLoaded(tabbedChrome.getActivityTab(),
                 WebappTestPage.getServiceWorkerUrl(mActivityTestRule.getTestServer()));
     }
@@ -318,7 +331,8 @@
         MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
                 mActivityTestRule.getActivity(), R.id.open_in_browser_id);
 
-        ChromeTabbedActivity tabbedChrome = waitFor(ChromeTabbedActivity.class);
+        ChromeTabbedActivity tabbedChrome =
+                ChromeActivityTestRule.waitFor(ChromeTabbedActivity.class);
         ThreadUtils.runOnUiThreadBlocking(
                 () -> tabbedChrome.getActivityTab().loadUrl(new LoadUrlParams(offOriginUrl())));
         ChromeTabUtils.waitForTabPageLoaded(tabbedChrome.getActivityTab(), offOriginUrl());
@@ -393,8 +407,13 @@
     }
 
     private WebappActivity runWebappActivityAndWaitForIdle(Intent intent) throws Exception {
-        mActivityTestRule.startWebappActivity(intent.putExtra(ShortcutHelper.EXTRA_URL,
-                WebappTestPage.getServiceWorkerUrl(mActivityTestRule.getTestServer())));
+        return runWebappActivityAndWaitForIdleWithUrl(
+                intent, WebappTestPage.getServiceWorkerUrl(mActivityTestRule.getTestServer()));
+    }
+
+    private WebappActivity runWebappActivityAndWaitForIdleWithUrl(Intent intent, String url)
+            throws Exception {
+        mActivityTestRule.startWebappActivity(intent.putExtra(ShortcutHelper.EXTRA_URL, url));
         mActivityTestRule.waitUntilSplashscreenHides();
         mActivityTestRule.waitUntilIdle();
         return mActivityTestRule.getActivity();
@@ -429,20 +448,6 @@
         clickNodeWithId("testId");
     }
 
-    @SuppressWarnings("unchecked")
-    private <T extends ChromeActivity> T waitFor(final Class<T> expectedClass) {
-        final Activity[] holder = new Activity[1];
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                holder[0] = ApplicationStatus.getLastTrackedFocusedActivity();
-                return holder[0] != null && expectedClass.isAssignableFrom(holder[0].getClass())
-                        && ((ChromeActivity) holder[0]).getActivityTab() != null;
-            }
-        });
-        return (T) holder[0];
-    }
-
     private void waitForExternalAppOrIntentPicker() {
         CriteriaHelper.pollUiThread(new Criteria() {
             @Override
diff --git a/chrome/browser/browsing_data/browsing_data_channel_id_helper.cc b/chrome/browser/browsing_data/browsing_data_channel_id_helper.cc
index 1498c985..03c3a33 100644
--- a/chrome/browser/browsing_data/browsing_data_channel_id_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_channel_id_helper.cc
@@ -86,9 +86,12 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(!callback.is_null());
 
-  net::ChannelIDStore* cert_store =
-      request_context_getter_->GetURLRequestContext()->
-      channel_id_service()->GetChannelIDStore();
+  net::ChannelIDService* channel_id_service =
+      request_context_getter_->GetURLRequestContext()->channel_id_service();
+  net::ChannelIDStore* cert_store = nullptr;
+  if (channel_id_service) {
+    cert_store = channel_id_service->GetChannelIDStore();
+  }
   if (cert_store) {
     cert_store->GetAllChannelIDs(base::Bind(
         &BrowsingDataChannelIDHelperImpl::OnFetchComplete, this, callback));
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index b4ccbf7c..1e7ca7d 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -584,8 +584,12 @@
   RegisterMediaEngagementPreloadComponent(cus, base::OnceClosure());
 
 #if defined(OS_WIN)
-#if defined(GOOGLE_CHROME_BUILD)
+  // SwReporter is only needed for official builds.  However, to enable testing
+  // on chromium build bots, it is always registered here and
+  // RegisterSwReporterComponent() has support for running only in official
+  // builds or tests.
   RegisterSwReporterComponent(cus);
+#if defined(GOOGLE_CHROME_BUILD)
   RegisterThirdPartyModuleListComponent(cus);
 #endif  // defined(GOOGLE_CHROME_BUILD)
 #endif  // defined(OS_WIN)
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 216765243..8163a71 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3954,35 +3954,33 @@
 }
 
 void ChromeContentBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories(
-    int render_process_id,
-    int render_frame_id,
+    int frame_tree_node_id,
     NonNetworkURLLoaderFactoryMap* factories) {
 #if BUILDFLAG(ENABLE_EXTENSIONS)
-  content::RenderProcessHost* process_host =
-      content::RenderProcessHost::FromID(render_process_id);
-  content::BrowserContext* browser_context = process_host->GetBrowserContext();
+  content::WebContents* web_contents =
+      content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
   factories->emplace(
       extensions::kExtensionScheme,
       extensions::CreateExtensionNavigationURLLoaderFactory(
-          render_process_id, render_frame_id,
-          extensions::ExtensionSystem::Get(browser_context)->info_map()));
+          web_contents->GetBrowserContext(),
+          !!extensions::WebViewGuest::FromWebContents(web_contents)));
 #endif
 }
 
 void ChromeContentBrowserClient::
     RegisterNonNetworkSubresourceURLLoaderFactories(
-        content::RenderFrameHost* frame_host,
-        const GURL& frame_url,
+        int render_process_id,
+        int render_frame_id,
         NonNetworkURLLoaderFactoryMap* factories) {
 #if BUILDFLAG(ENABLE_EXTENSIONS)
-  content::RenderProcessHost* process_host = frame_host->GetProcess();
-  content::BrowserContext* browser_context = process_host->GetBrowserContext();
-  auto factory = extensions::MaybeCreateExtensionSubresourceURLLoaderFactory(
-      process_host->GetID(), frame_host->GetRoutingID(), frame_url,
-      extensions::ExtensionSystem::Get(browser_context)->info_map());
+  auto factory = extensions::CreateExtensionURLLoaderFactory(render_process_id,
+                                                             render_frame_id);
   if (factory)
     factories->emplace(extensions::kExtensionScheme, std::move(factory));
 
+  content::RenderFrameHost* frame_host =
+      RenderFrameHost::FromID(render_process_id, render_frame_id);
+
   // This logic should match
   // ChromeExtensionWebContentsObserver::RenderFrameCreated.
   WebContents* web_contents = WebContents::FromRenderFrameHost(frame_host);
@@ -3995,7 +3993,7 @@
       InstantServiceFactory::GetForProfile(profile);
   // The test below matches what's done by ShouldServiceRequestIOThread in
   // local_ntp_source.cc.
-  if (instant_service->IsInstantProcess(frame_host->GetProcess()->GetID())) {
+  if (instant_service->IsInstantProcess(render_process_id)) {
     factories->emplace(
         chrome::kChromeSearchScheme,
         content::CreateWebUIURLLoader(
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 56b082e..8f75f762 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -378,12 +378,11 @@
       content::NavigationUIData* navigation_ui_data,
       int frame_tree_node_id) override;
   void RegisterNonNetworkNavigationURLLoaderFactories(
-      int render_process_id,
-      int render_frame_id,
+      int frame_tree_node_id,
       NonNetworkURLLoaderFactoryMap* factories) override;
   void RegisterNonNetworkSubresourceURLLoaderFactories(
-      content::RenderFrameHost* frame_host,
-      const GURL& frame_url,
+      int render_process_id,
+      int render_frame_id,
       NonNetworkURLLoaderFactoryMap* factories) override;
   bool WillCreateURLLoaderFactory(
       content::RenderFrameHost* frame,
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
index bf93713..e3387ad 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -18,6 +18,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
@@ -643,23 +644,37 @@
   Respond(NoArguments());
 }
 
-bool IsCrostiniEnabled() {
+namespace {
+bool IsCrostiniEnabledForProfile(Profile* profile) {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
              chromeos::switches::kCrostiniFiles) &&
-         crostini::CrostiniManager::IsCrosTerminaInstalled();
+         IsCrostiniUIAllowedForProfile(profile) && IsCrostiniEnabled(profile);
+}
 }
 
 ExtensionFunction::ResponseAction
 FileManagerPrivateIsCrostiniEnabledFunction::Run() {
   return RespondNow(
-      OneArgument(std::make_unique<base::Value>(IsCrostiniEnabled())));
+      OneArgument(std::make_unique<base::Value>(IsCrostiniEnabledForProfile(
+          Profile::FromBrowserContext(browser_context())))));
 }
 
-ExtensionFunction::ResponseAction
-FileManagerPrivateMountCrostiniContainerFunction::Run() {
-  // TOOD(https://crbug.com/832509): implement MountCrostiniContainer.
-  DCHECK(IsCrostiniEnabled());
-  return RespondNow(NoArguments());
+bool FileManagerPrivateMountCrostiniContainerFunction::RunAsync() {
+  Profile* profile = Profile::FromBrowserContext(browser_context());
+  DCHECK(IsCrostiniEnabledForProfile(profile));
+  crostini::CrostiniManager::GetInstance()->RestartCrostini(
+      profile, kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
+      base::BindOnce(
+          &FileManagerPrivateMountCrostiniContainerFunction::RestartCallback,
+          this));
+  return true;
+}
+
+void FileManagerPrivateMountCrostiniContainerFunction::RestartCallback(
+    crostini::ConciergeClientResult result) {
+  SetResult(std::make_unique<base::Value>(
+      result == crostini::ConciergeClientResult::SUCCESS));
+  SendResponse(true);
 }
 
 FileManagerPrivateInternalGetCustomActionsFunction::
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
index c745985..92a533b8 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
@@ -26,6 +26,10 @@
 class RecentFile;
 }  // namespace chromeos
 
+namespace crostini {
+enum class ConciergeClientResult;
+}
+
 namespace file_manager {
 namespace util {
 struct EntryDefinition;
@@ -278,7 +282,7 @@
 // Implements the chrome.fileManagerPrivate.mountCrostiniContainer method.
 // Starts and mounts crostini container.
 class FileManagerPrivateMountCrostiniContainerFunction
-    : public UIThreadExtensionFunction {
+    : public LoggedAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fileManagerPrivate.mountCrostiniContainer",
                              FILEMANAGERPRIVATE_MOUNTCROSTINICONTAINER)
@@ -286,7 +290,8 @@
  protected:
   ~FileManagerPrivateMountCrostiniContainerFunction() override {}
 
-  ResponseAction Run() override;
+  bool RunAsync() override;
+  void RestartCallback(crostini::ConciergeClientResult);
 };
 
 // Implements the chrome.fileManagerPrivate.getCustomActions method.
diff --git a/chrome/browser/chromeos/file_manager/audio_player_browsertest.cc b/chrome/browser/chromeos/file_manager/audio_player_browsertest.cc
index 1640ba6..3d3035c 100644
--- a/chrome/browser/chromeos/file_manager/audio_player_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/audio_player_browsertest.cc
@@ -9,6 +9,9 @@
 template <GuestMode MODE>
 class AudioPlayerBrowserTestBase : public FileManagerBrowserTestBase {
  public:
+  AudioPlayerBrowserTestBase() = default;
+
+ protected:
   GuestMode GetGuestMode() const override { return MODE; }
 
   const char* GetTestCaseName() const override {
@@ -19,11 +22,12 @@
     return "audio_player_test_manifest.json";
   }
 
- protected:
   void set_test_case_name(const std::string& name) { test_case_name_ = name; }
 
  private:
   std::string test_case_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioPlayerBrowserTestBase);
 };
 
 typedef AudioPlayerBrowserTestBase<NOT_IN_GUEST_MODE> AudioPlayerBrowserTest;
@@ -61,4 +65,14 @@
   StartTest();
 }
 
+IN_PROC_BROWSER_TEST_F(AudioPlayerBrowserTest, ChangeTracksPlayList) {
+  set_test_case_name("changeTracksPlayList");
+  StartTest();
+}
+
+IN_PROC_BROWSER_TEST_F(AudioPlayerBrowserTest, ChangeTracksPlayListIcon) {
+  set_test_case_name("changeTracksPlayListIcon");
+  StartTest();
+}
+
 }  // namespace file_manager
diff --git a/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc b/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc
index d6bcee5..2d3645b3a 100644
--- a/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc
+++ b/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
+
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -108,7 +110,7 @@
   bool HasMultipleFileTypeChoicesImpl() override { return false; }
 
  private:
-  ~FakeSelectFileDialog() override {}
+  ~FakeSelectFileDialog() override = default;
 };
 
 class FakeSelectFileDialogFactory : public ui::SelectFileDialogFactory {
@@ -279,8 +281,8 @@
     FLAGS_LAZY_FILE_HANDLER = 1 << 2
   };
 
-  FileSystemExtensionApiTestBase() {}
-  ~FileSystemExtensionApiTestBase() override {}
+  FileSystemExtensionApiTestBase() = default;
+  ~FileSystemExtensionApiTestBase() override = default;
 
   void SetUp() override {
     InitTestFileSystem();
@@ -377,8 +379,8 @@
 // Tests for a native local file system.
 class LocalFileSystemExtensionApiTest : public FileSystemExtensionApiTestBase {
  public:
-  LocalFileSystemExtensionApiTest() {}
-  ~LocalFileSystemExtensionApiTest() override {}
+  LocalFileSystemExtensionApiTest() = default;
+  ~LocalFileSystemExtensionApiTest() override = default;
 
   // FileSystemExtensionApiTestBase override.
   void InitTestFileSystem() override {
@@ -409,8 +411,8 @@
 class RestrictedFileSystemExtensionApiTest
     : public FileSystemExtensionApiTestBase {
  public:
-  RestrictedFileSystemExtensionApiTest() {}
-  ~RestrictedFileSystemExtensionApiTest() override {}
+  RestrictedFileSystemExtensionApiTest() = default;
+  ~RestrictedFileSystemExtensionApiTest() override = default;
 
   // FileSystemExtensionApiTestBase override.
   void InitTestFileSystem() override {
@@ -441,8 +443,8 @@
 // Tests for a drive file system.
 class DriveFileSystemExtensionApiTest : public FileSystemExtensionApiTestBase {
  public:
-  DriveFileSystemExtensionApiTest() {}
-  ~DriveFileSystemExtensionApiTest() override {}
+  DriveFileSystemExtensionApiTest() = default;
+  ~DriveFileSystemExtensionApiTest() override = default;
 
   // FileSystemExtensionApiTestBase override.
   void InitTestFileSystem() override {
@@ -455,9 +457,10 @@
     create_drive_integration_service_ = base::Bind(
         &DriveFileSystemExtensionApiTest::CreateDriveIntegrationService,
         base::Unretained(this));
-    service_factory_for_test_.reset(
-        new DriveIntegrationServiceFactory::ScopedFactoryForTest(
-            &create_drive_integration_service_));
+    service_factory_for_test_ =
+        std::make_unique<DriveIntegrationServiceFactory::ScopedFactoryForTest>(
+
+            &create_drive_integration_service_);
   }
 
   // FileSystemExtensionApiTestBase override.
@@ -503,7 +506,7 @@
 class MultiProfileDriveFileSystemExtensionApiTest :
     public FileSystemExtensionApiTestBase {
  public:
-  MultiProfileDriveFileSystemExtensionApiTest() {}
+  MultiProfileDriveFileSystemExtensionApiTest() = default;
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     FileSystemExtensionApiTestBase::SetUpCommandLine(command_line);
@@ -540,9 +543,10 @@
         &MultiProfileDriveFileSystemExtensionApiTest::
             CreateDriveIntegrationService,
         base::Unretained(this));
-    service_factory_for_test_.reset(
-        new DriveIntegrationServiceFactory::ScopedFactoryForTest(
-            &create_drive_integration_service_));
+    service_factory_for_test_ =
+        std::make_unique<DriveIntegrationServiceFactory::ScopedFactoryForTest>(
+
+            &create_drive_integration_service_);
   }
 
   void AddTestMountPoint() override {
@@ -595,8 +599,8 @@
 class LocalAndDriveFileSystemExtensionApiTest
     : public FileSystemExtensionApiTestBase {
  public:
-  LocalAndDriveFileSystemExtensionApiTest() {}
-  ~LocalAndDriveFileSystemExtensionApiTest() override {}
+  LocalAndDriveFileSystemExtensionApiTest() = default;
+  ~LocalAndDriveFileSystemExtensionApiTest() override = default;
 
   // FileSystemExtensionApiTestBase override.
   void InitTestFileSystem() override {
@@ -613,9 +617,10 @@
     create_drive_integration_service_ = base::Bind(
         &LocalAndDriveFileSystemExtensionApiTest::CreateDriveIntegrationService,
         base::Unretained(this));
-    service_factory_for_test_.reset(
-        new DriveIntegrationServiceFactory::ScopedFactoryForTest(
-            &create_drive_integration_service_));
+    service_factory_for_test_ =
+        std::make_unique<DriveIntegrationServiceFactory::ScopedFactoryForTest>(
+
+            &create_drive_integration_service_);
   }
 
   // FileSystemExtensionApiTestBase override.
diff --git a/chrome/browser/chromeos/file_manager/fake_disk_mount_manager.cc b/chrome/browser/chromeos/file_manager/fake_disk_mount_manager.cc
index 91f0699..4f78bda1 100644
--- a/chrome/browser/chromeos/file_manager/fake_disk_mount_manager.cc
+++ b/chrome/browser/chromeos/file_manager/fake_disk_mount_manager.cc
@@ -32,11 +32,9 @@
     chromeos::MountAccessMode access_mode)
     : access_mode(access_mode) {}
 
-FakeDiskMountManager::FakeDiskMountManager() {
-}
+FakeDiskMountManager::FakeDiskMountManager() = default;
 
-FakeDiskMountManager::~FakeDiskMountManager() {
-}
+FakeDiskMountManager::~FakeDiskMountManager() = default;
 
 void FakeDiskMountManager::AddObserver(Observer* observer) {
   DCHECK(observer);
@@ -76,8 +74,8 @@
                                      const std::string& mount_label,
                                      chromeos::MountType type,
                                      chromeos::MountAccessMode access_mode) {
-  mount_requests_.push_back(
-      MountRequest(source_path, source_format, mount_label, type, access_mode));
+  mount_requests_.emplace_back(source_path, source_format, mount_label, type,
+                               access_mode);
 
   const MountPointInfo mount_point(
       source_path,
@@ -94,7 +92,7 @@
 void FakeDiskMountManager::UnmountPath(const std::string& mount_path,
                                        chromeos::UnmountOptions options,
                                        const UnmountPathCallback& callback) {
-  unmount_requests_.push_back(UnmountRequest(mount_path, options));
+  unmount_requests_.emplace_back(mount_path, options);
 
   MountPointMap::iterator iter = mount_points_.find(mount_path);
   if (iter == mount_points_.end())
@@ -114,7 +112,7 @@
 
 void FakeDiskMountManager::RemountAllRemovableDrives(
     chromeos::MountAccessMode access_mode) {
-  remount_all_requests_.push_back(RemountAllRequest(access_mode));
+  remount_all_requests_.emplace_back(access_mode);
 }
 
 bool FakeDiskMountManager::FinishAllUnmountPathRequests() {
diff --git a/chrome/browser/chromeos/file_manager/file_browser_handlers.cc b/chrome/browser/chromeos/file_manager/file_browser_handlers.cc
index 2b896572..f3e420a8 100644
--- a/chrome/browser/chromeos/file_manager/file_browser_handlers.cc
+++ b/chrome/browser/chromeos/file_manager/file_browser_handlers.cc
@@ -93,7 +93,7 @@
     if (handler_iter->get()->id() == action_id)
       return handler_iter->get();
   }
-  return NULL;
+  return nullptr;
 }
 
 std::string EscapedUtf8ToLower(const std::string& str) {
@@ -280,7 +280,7 @@
       weak_ptr_factory_(this) {
 }
 
-FileBrowserHandlerExecutor::~FileBrowserHandlerExecutor() {}
+FileBrowserHandlerExecutor::~FileBrowserHandlerExecutor() = default;
 
 void FileBrowserHandlerExecutor::Execute(
     const std::vector<FileSystemURL>& file_urls,
@@ -345,7 +345,7 @@
   if (handler_pid > 0) {
     SetupPermissionsAndDispatchEvent(std::move(file_definition_list),
                                      std::move(entry_definition_list),
-                                     handler_pid, NULL);
+                                     handler_pid, nullptr);
   } else {
     // We have to wake the handler background page before we proceed.
     extensions::LazyBackgroundTaskQueue* queue =
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index dfcdd19..01c518b 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -27,6 +27,9 @@
       public FileManagerBrowserTestBase,
       public ::testing::WithParamInterface<TestParameter> {
  public:
+  FileManagerBrowserTest() = default;
+
+ protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     FileManagerBrowserTestBase::SetUpCommandLine(command_line);
 
@@ -54,6 +57,8 @@
     // crbug.com/482121 crbug.com/480491
     return test_case_name.find("tabindex") != std::string::npos;
   }
+
+  DISALLOW_COPY_AND_ASSIGN(FileManagerBrowserTest);
 };
 
 IN_PROC_BROWSER_TEST_P(FileManagerBrowserTest, Test) {
@@ -65,11 +70,17 @@
 class FileManagerBrowserTestWithLegacyEventDispatch
     : public FileManagerBrowserTest {
  public:
+  FileManagerBrowserTestWithLegacyEventDispatch() = default;
+
+ protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     FileManagerBrowserTest::SetUpCommandLine(command_line);
     command_line->AppendSwitchASCII("disable-blink-features",
                                     "TrustedEventsDefaultAction");
   }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FileManagerBrowserTestWithLegacyEventDispatch);
 };
 
 IN_PROC_BROWSER_TEST_P(FileManagerBrowserTestWithLegacyEventDispatch, Test) {
@@ -484,6 +495,9 @@
 
 // Test fixture class for testing multi-profile features.
 class MultiProfileFileManagerBrowserTest : public FileManagerBrowserTestBase {
+ public:
+  MultiProfileFileManagerBrowserTest() = default;
+
  protected:
   // Enables multi-profiles.
   void SetUpCommandLine(base::CommandLine* command_line) override {
@@ -531,9 +545,6 @@
     return profile ? profile : FileManagerBrowserTestBase::profile();
   }
 
-  // Sets the test case name (used as a function name in test_cases.js to call.)
-  void set_test_case_name(const std::string& name) { test_case_name_ = name; }
-
   // Adds a new user for testing to the current session.
   void AddUser(const TestAccountInfo& info, bool log_in) {
     base::ScopedAllowBlockingForTesting allow_blocking;
@@ -567,8 +578,12 @@
     return "file_manager_test_manifest.json";
   }
 
+  void set_test_case_name(const std::string& name) { test_case_name_ = name; }
+
  private:
   std::string test_case_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(MultiProfileFileManagerBrowserTest);
 };
 
 // Fails on official build. http://crbug.com/429294
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
index 142dea94..cf7bdb27 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h"
 
+#include <memory>
 #include <stddef.h>
 
 #include "base/containers/circular_deque.h"
@@ -228,13 +229,15 @@
   base::OnceClosure quit_closure_;
   base::circular_deque<Message> messages_;
   content::NotificationRegistrar registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileManagerTestMessageListener);
 };
 
 // Test volume.
 class TestVolume {
  protected:
   explicit TestVolume(const std::string& name) : name_(name) {}
-  virtual ~TestVolume() {}
+  virtual ~TestVolume() = default;
 
   bool CreateRootDirectory(const Profile* profile) {
     if (root_initialized_)
@@ -263,6 +266,8 @@
   base::ScopedTempDir root_;
   bool root_initialized_ = false;
   std::string name_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestVolume);
 };
 
 }  // anonymous namespace
@@ -271,7 +276,7 @@
 class LocalTestVolume : public TestVolume {
  public:
   explicit LocalTestVolume(const std::string& name) : TestVolume(name) {}
-  ~LocalTestVolume() override {}
+  ~LocalTestVolume() override = default;
 
   // Adds this local volume. Returns true on success.
   virtual bool Mount(Profile* profile) = 0;
@@ -295,6 +300,7 @@
             << "Failed to create a directory: " << target_path.value();
         break;
     }
+
     ASSERT_TRUE(UpdateModifiedTime(entry));
   }
 
@@ -316,17 +322,20 @@
         return false;
       return UpdateModifiedTime(it->second);
     }
+
     return true;
   }
 
   std::map<base::FilePath, const TestEntryInfo> entries_;
+
+  DISALLOW_COPY_AND_ASSIGN(LocalTestVolume);
 };
 
 // DownloadsTestVolume: local test volume for the "Downloads" directory.
 class DownloadsTestVolume : public LocalTestVolume {
  public:
   DownloadsTestVolume() : LocalTestVolume("Downloads") {}
-  ~DownloadsTestVolume() override {}
+  ~DownloadsTestVolume() override = default;
 
   bool Mount(Profile* profile) override {
     if (!CreateRootDirectory(profile))
@@ -334,6 +343,9 @@
     auto* volume = VolumeManager::Get(profile);
     return volume->RegisterDownloadsDirectoryForTesting(root_path());
   }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DownloadsTestVolume);
 };
 
 // FakeTestVolume: local test volume with a given volume and device type.
@@ -345,7 +357,7 @@
       : LocalTestVolume(name),
         volume_type_(volume_type),
         device_type_(device_type) {}
-  ~FakeTestVolume() override {}
+  ~FakeTestVolume() override = default;
 
   // Add the fake test volume entries.
   bool PrepareTestEntries(Profile* profile) {
@@ -387,13 +399,15 @@
   const VolumeType volume_type_;
   const chromeos::DeviceType device_type_;
   const bool read_only_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeTestVolume);
 };
 
 // DriveTestVolume: test volume for Google Drive.
 class DriveTestVolume : public TestVolume {
  public:
   DriveTestVolume() : TestVolume("drive") {}
-  ~DriveTestVolume() override {}
+  ~DriveTestVolume() override = default;
 
   void CreateEntry(const TestEntryInfo& entry) {
     const base::FilePath path =
@@ -525,6 +539,8 @@
   drive::FakeDriveService* fake_drive_service_ = nullptr;
   // Integration service used for testing: not owned.
   drive::DriveIntegrationService* integration_service_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(DriveTestVolume);
 };
 
 FileManagerBrowserTestBase::FileManagerBrowserTestBase() = default;
@@ -557,15 +573,16 @@
 void FileManagerBrowserTestBase::SetUpInProcessBrowserTestFixture() {
   ExtensionApiTest::SetUpInProcessBrowserTestFixture();
 
-  local_volume_.reset(new DownloadsTestVolume);
+  local_volume_ = std::make_unique<DownloadsTestVolume>();
 
   if (!IsGuestModeTest()) {
     create_drive_integration_service_ =
         base::Bind(&FileManagerBrowserTestBase::CreateDriveIntegrationService,
                    base::Unretained(this));
-    service_factory_for_test_.reset(
-        new drive::DriveIntegrationServiceFactory::ScopedFactoryForTest(
-            &create_drive_integration_service_));
+    service_factory_for_test_ = std::make_unique<
+        drive::DriveIntegrationServiceFactory::ScopedFactoryForTest>(
+
+        &create_drive_integration_service_);
   }
 }
 
@@ -743,16 +760,16 @@
   }
 
   if (name == "mountFakeUsb") {
-    usb_volume_.reset(new FakeTestVolume("fake-usb",
-                                         VOLUME_TYPE_REMOVABLE_DISK_PARTITION,
-                                         chromeos::DEVICE_TYPE_USB));
+    usb_volume_ = std::make_unique<FakeTestVolume>(
+        "fake-usb", VOLUME_TYPE_REMOVABLE_DISK_PARTITION,
+        chromeos::DEVICE_TYPE_USB);
     ASSERT_TRUE(usb_volume_->Mount(profile()));
     return;
   }
 
   if (name == "mountFakeMtp") {
-    mtp_volume_.reset(new FakeTestVolume("fake-mtp", VOLUME_TYPE_MTP,
-                                         chromeos::DEVICE_TYPE_UNKNOWN));
+    mtp_volume_ = std::make_unique<FakeTestVolume>(
+        "fake-mtp", VOLUME_TYPE_MTP, chromeos::DEVICE_TYPE_UNKNOWN);
     ASSERT_TRUE(mtp_volume_->PrepareTestEntries(profile()));
 
     ASSERT_TRUE(mtp_volume_->Mount(profile()));
@@ -799,7 +816,8 @@
 
 drive::DriveIntegrationService*
 FileManagerBrowserTestBase::CreateDriveIntegrationService(Profile* profile) {
-  drive_volumes_[profile->GetOriginalProfile()].reset(new DriveTestVolume());
+  drive_volumes_[profile->GetOriginalProfile()] =
+      std::make_unique<DriveTestVolume>();
   return drive_volumes_[profile->GetOriginalProfile()]
       ->CreateDriveIntegrationService(profile);
 }
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
index 3903668..836e9ca 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
@@ -94,6 +94,8 @@
       service_factory_for_test_;
 
   std::unique_ptr<NotificationDisplayServiceTester> display_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileManagerBrowserTestBase);
 };
 
 }  // namespace file_manager
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.cc b/chrome/browser/chromeos/file_manager/file_tasks.cc
index 357c3b4..51501ef4 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks.cc
@@ -200,7 +200,7 @@
       is_default_(is_default),
       is_generic_file_handler_(is_generic_file_handler) {}
 
-FullTaskDescriptor::~FullTaskDescriptor() {}
+FullTaskDescriptor::~FullTaskDescriptor() = default;
 
 FullTaskDescriptor::FullTaskDescriptor(const FullTaskDescriptor& other) =
     default;
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.h b/chrome/browser/chromeos/file_manager/file_tasks.h
index edbcd24..41cb8f3 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.h
+++ b/chrome/browser/chromeos/file_manager/file_tasks.h
@@ -163,8 +163,7 @@
         task_type(in_task_type),
         action_id(in_action_id) {
   }
-  TaskDescriptor() {
-  }
+  TaskDescriptor() = default;
 
   std::string app_id;
   TaskType task_type;
diff --git a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
index 75a8856..4b7ee13 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
@@ -203,14 +203,14 @@
   app_resources.push_back(std::move(bar_app));
   google_apis::AppList app_list;
   app_list.set_items(std::move(app_resources));
-  drive::DriveAppRegistry drive_app_registry(NULL);
+  drive::DriveAppRegistry drive_app_registry(nullptr);
   drive_app_registry.UpdateFromAppList(app_list);
 
   // Find apps for a "text/plain" file. Foo.app and Bar.app should be found.
   std::vector<extensions::EntryInfo> entries;
-  entries.push_back(extensions::EntryInfo(
+  entries.emplace_back(
       drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
-      "text/plain", false));
+      "text/plain", false);
   std::vector<FullTaskDescriptor> tasks;
   FindDriveAppTasks(drive_app_registry, entries, &tasks);
   ASSERT_EQ(2U, tasks.size());
@@ -226,12 +226,12 @@
   // Find apps for "text/plain" and "text/html" files. Only Foo.app should be
   // found.
   entries.clear();
-  entries.push_back(extensions::EntryInfo(
+  entries.emplace_back(
       drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
-      "text/plain", false));
-  entries.push_back(extensions::EntryInfo(
+      "text/plain", false);
+  entries.emplace_back(
       drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.html"),
-      "text/html", false));
+      "text/html", false);
   tasks.clear();
   FindDriveAppTasks(drive_app_registry, entries, &tasks);
   ASSERT_EQ(1U, tasks.size());
@@ -239,8 +239,8 @@
   EXPECT_EQ("foo_app_id", tasks[0].task_descriptor().app_id);
 
   // Add a "text/plain" file not on Drive. No tasks should be found.
-  entries.push_back(extensions::EntryInfo(
-      base::FilePath::FromUTF8Unsafe("not_on_drive.txt"), "text/plain", false));
+  entries.emplace_back(base::FilePath::FromUTF8Unsafe("not_on_drive.txt"),
+                       "text/plain", false);
   tasks.clear();
   FindDriveAppTasks(drive_app_registry, entries, &tasks);
   // Confirm no tasks are found.
@@ -261,17 +261,17 @@
                                TASK_TYPE_FILE_HANDLER,
                                "action-id");
   std::vector<FullTaskDescriptor> tasks;
-  tasks.push_back(FullTaskDescriptor(
-      text_app_task, "Text.app", Verb::VERB_OPEN_WITH,
-      GURL("http://example.com/text_app.png"), false /* is_default */,
-      false /* is_generic_file_handler */));
-  tasks.push_back(FullTaskDescriptor(
-      nice_app_task, "Nice.app", Verb::VERB_ADD_TO,
-      GURL("http://example.com/nice_app.png"), false /* is_default */,
-      false /* is_generic_file_handler */));
+  tasks.emplace_back(text_app_task, "Text.app", Verb::VERB_OPEN_WITH,
+                     GURL("http://example.com/text_app.png"),
+                     false /* is_default */,
+                     false /* is_generic_file_handler */);
+  tasks.emplace_back(nice_app_task, "Nice.app", Verb::VERB_ADD_TO,
+                     GURL("http://example.com/nice_app.png"),
+                     false /* is_default */,
+                     false /* is_generic_file_handler */);
   std::vector<extensions::EntryInfo> entries;
-  entries.push_back(extensions::EntryInfo(
-      base::FilePath::FromUTF8Unsafe("foo.txt"), "text/plain", false));
+  entries.emplace_back(base::FilePath::FromUTF8Unsafe("foo.txt"), "text/plain",
+                       false);
 
   // None of them should be chosen as default, as nothing is set in the
   // preferences.
@@ -322,13 +322,13 @@
                                 TASK_TYPE_FILE_BROWSER_HANDLER,
                                 "view-in-browser");
   std::vector<FullTaskDescriptor> tasks;
-  tasks.push_back(FullTaskDescriptor(
-      files_app_task, "View in browser", Verb::VERB_OPEN_WITH,
-      GURL("http://example.com/some_icon.png"), false /* is_default */,
-      false /* is_generic_file_handler */));
+  tasks.emplace_back(files_app_task, "View in browser", Verb::VERB_OPEN_WITH,
+                     GURL("http://example.com/some_icon.png"),
+                     false /* is_default */,
+                     false /* is_generic_file_handler */);
   std::vector<extensions::EntryInfo> entries;
-  entries.push_back(extensions::EntryInfo(
-      base::FilePath::FromUTF8Unsafe("foo.txt"), "text/plain", false));
+  entries.emplace_back(base::FilePath::FromUTF8Unsafe("foo.txt"), "text/plain",
+                       false);
 
   // The internal file browser handler should be chosen as default, as it's a
   // fallback file browser handler.
@@ -346,13 +346,13 @@
   TaskDescriptor files_app_task(kTextEditorAppId, TASK_TYPE_FILE_HANDLER,
                                 "Text");
   std::vector<FullTaskDescriptor> tasks;
-  tasks.push_back(FullTaskDescriptor(
+  tasks.emplace_back(
       files_app_task, "Text", Verb::VERB_OPEN_WITH,
       GURL("chrome://extension-icon/mmfbcljfglbokpmkimbfghdkjmjhdgbg/16/1"),
-      false /* is_default */, false /* is_generic_file_handler */));
+      false /* is_default */, false /* is_generic_file_handler */);
   std::vector<extensions::EntryInfo> entries;
-  entries.push_back(extensions::EntryInfo(
-      base::FilePath::FromUTF8Unsafe("foo.txt"), "text/plain", false));
+  entries.emplace_back(base::FilePath::FromUTF8Unsafe("foo.txt"), "text/plain",
+                       false);
 
   // The text editor app should be chosen as default, as it's a fallback file
   // browser handler.
@@ -370,13 +370,13 @@
   TaskDescriptor files_app_task(kAudioPlayerAppId, TASK_TYPE_FILE_HANDLER,
                                 "Audio Player");
   std::vector<FullTaskDescriptor> tasks;
-  tasks.push_back(FullTaskDescriptor(
+  tasks.emplace_back(
       files_app_task, "Audio Player", Verb::VERB_OPEN_WITH,
       GURL("chrome://extension-icon/cjbfomnbifhcdnihkgipgfcihmgjfhbf/32/1"),
-      false /* is_default */, false /* is_generic_file_handler */));
+      false /* is_default */, false /* is_generic_file_handler */);
   std::vector<extensions::EntryInfo> entries;
-  entries.push_back(extensions::EntryInfo(
-      base::FilePath::FromUTF8Unsafe("sound.wav"), "audio/wav", false));
+  entries.emplace_back(base::FilePath::FromUTF8Unsafe("sound.wav"), "audio/wav",
+                       false);
 
   // The Audio Player app should be chosen as default, as it's a fallback file
   // browser handler.
@@ -395,14 +395,14 @@
       extension_misc::kQuickOfficeComponentExtensionId, TASK_TYPE_FILE_HANDLER,
       "Office Editing for Docs, Sheets & Slides");
   std::vector<FullTaskDescriptor> tasks;
-  tasks.push_back(FullTaskDescriptor(
+  tasks.emplace_back(
       files_app_task, "Office Editing for Docs, Sheets & Slides",
       Verb::VERB_OPEN_WITH,
       GURL("chrome://extension-icon/bpmcpldpdmajfigpchkicefoigmkfalc/32/1"),
-      false /* is_default */, false /* is_generic_file_handler */));
+      false /* is_default */, false /* is_generic_file_handler */);
   std::vector<extensions::EntryInfo> entries;
-  entries.push_back(extensions::EntryInfo(
-      base::FilePath::FromUTF8Unsafe("slides.pptx"), "", false));
+  entries.emplace_back(base::FilePath::FromUTF8Unsafe("slides.pptx"), "",
+                       false);
 
   // The Office Editing app should be chosen as default, as it's a fallback
   // file browser handler.
@@ -416,14 +416,14 @@
   using FileHandlerInfo = extensions::FileHandlerInfo;
 
   std::vector<extensions::EntryInfo> entries_1;
-  entries_1.push_back(extensions::EntryInfo(
-      base::FilePath(FILE_PATH_LITERAL("foo.jpg")), "image/jpeg", false));
-  entries_1.push_back(extensions::EntryInfo(
-      base::FilePath(FILE_PATH_LITERAL("bar.txt")), "text/plain", false));
+  entries_1.emplace_back(base::FilePath(FILE_PATH_LITERAL("foo.jpg")),
+                         "image/jpeg", false);
+  entries_1.emplace_back(base::FilePath(FILE_PATH_LITERAL("bar.txt")),
+                         "text/plain", false);
 
   std::vector<extensions::EntryInfo> entries_2;
-  entries_2.push_back(extensions::EntryInfo(
-      base::FilePath(FILE_PATH_LITERAL("foo.ics")), "text/calendar", false));
+  entries_2.emplace_back(base::FilePath(FILE_PATH_LITERAL("foo.ics")),
+                         "text/calendar", false);
 
   // extensions: ["*"]
   FileHandlerInfo file_handler_info_1;
@@ -484,8 +484,7 @@
   // path_directory_set not empty.
   FileHandlerInfo file_handler_info_11;
   std::vector<extensions::EntryInfo> entries_3;
-  entries_3.push_back(extensions::EntryInfo(
-      base::FilePath(FILE_PATH_LITERAL("dir1")), "", true));
+  entries_3.emplace_back(base::FilePath(FILE_PATH_LITERAL("dir1")), "", true);
   EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_11, entries_3));
 }
 
@@ -493,7 +492,8 @@
 class FileManagerFileTasksComplexTest : public testing::Test {
  protected:
   FileManagerFileTasksComplexTest()
-      : command_line_(base::CommandLine::NO_PROGRAM), extension_service_(NULL) {
+      : command_line_(base::CommandLine::NO_PROGRAM),
+        extension_service_(nullptr) {
     extensions::TestExtensionSystem* test_extension_system =
         static_cast<extensions::TestExtensionSystem*>(
             extensions::ExtensionSystem::Get(&test_profile_));
@@ -603,10 +603,9 @@
 
   // Find apps for a "text/plain" file. Foo.app and Bar.app should be found.
   std::vector<extensions::EntryInfo> entries;
-  entries.push_back(
-      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
-                                .AppendASCII("foo.txt"),
-                            "text/plain", false));
+  entries.emplace_back(drive::util::GetDriveMountPointPath(&test_profile_)
+                           .AppendASCII("foo.txt"),
+                       "text/plain", false);
 
   std::vector<FullTaskDescriptor> tasks;
   FindFileHandlerTasks(&test_profile_, entries, &tasks);
@@ -623,14 +622,12 @@
   // Find apps for "text/plain" and "text/html" files. Only Foo.app should be
   // found.
   entries.clear();
-  entries.push_back(
-      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
-                                .AppendASCII("foo.txt"),
-                            "text/plain", false));
-  entries.push_back(
-      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
-                                .AppendASCII("foo.html"),
-                            "text/html", false));
+  entries.emplace_back(drive::util::GetDriveMountPointPath(&test_profile_)
+                           .AppendASCII("foo.txt"),
+                       "text/plain", false);
+  entries.emplace_back(drive::util::GetDriveMountPointPath(&test_profile_)
+                           .AppendASCII("foo.html"),
+                       "text/html", false);
   tasks.clear();
   FindFileHandlerTasks(&test_profile_, entries, &tasks);
   ASSERT_EQ(1U, tasks.size());
@@ -638,8 +635,8 @@
   EXPECT_EQ(kFooId, tasks[0].task_descriptor().app_id);
 
   // Add an "image/png" file. No tasks should be found.
-  entries.push_back(extensions::EntryInfo(
-      base::FilePath::FromUTF8Unsafe("foo.png"), "image/png", false));
+  entries.emplace_back(base::FilePath::FromUTF8Unsafe("foo.png"), "image/png",
+                       false);
   tasks.clear();
   FindFileHandlerTasks(&test_profile_, entries, &tasks);
   // Confirm no tasks are found.
@@ -704,7 +701,7 @@
 
   // Find apps for a ".txt" file. Foo.app and Bar.app should be found.
   std::vector<GURL> file_urls;
-  file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
+  file_urls.emplace_back("filesystem:chrome-extension://id/dir/foo.txt");
 
   std::vector<FullTaskDescriptor> tasks;
   FindFileBrowserHandlerTasks(&test_profile_, file_urls, &tasks);
@@ -720,8 +717,8 @@
 
   // Find apps for ".txt" and ".html" files. Only Foo.app should be found.
   file_urls.clear();
-  file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
-  file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.html"));
+  file_urls.emplace_back("filesystem:chrome-extension://id/dir/foo.txt");
+  file_urls.emplace_back("filesystem:chrome-extension://id/dir/foo.html");
   tasks.clear();
   FindFileBrowserHandlerTasks(&test_profile_, file_urls, &tasks);
   ASSERT_EQ(1U, tasks.size());
@@ -729,7 +726,7 @@
   EXPECT_EQ(kFooId, tasks[0].task_descriptor().app_id);
 
   // Add an ".png" file. No tasks should be found.
-  file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.png"));
+  file_urls.emplace_back("filesystem:chrome-extension://id/dir/foo.png");
   tasks.clear();
   FindFileBrowserHandlerTasks(&test_profile_, file_urls, &tasks);
   // Confirm no tasks are found.
@@ -814,17 +811,16 @@
   app_resources.push_back(std::move(baz_app));
   google_apis::AppList app_list;
   app_list.set_items(std::move(app_resources));
-  drive::DriveAppRegistry drive_app_registry(NULL);
+  drive::DriveAppRegistry drive_app_registry(nullptr);
   drive_app_registry.UpdateFromAppList(app_list);
 
   // Find apps for "foo.txt". All apps should be found.
   std::vector<extensions::EntryInfo> entries;
   std::vector<GURL> file_urls;
-  entries.push_back(
-      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
-                                .AppendASCII("foo.txt"),
-                            "text/plain", false));
-  file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
+  entries.emplace_back(drive::util::GetDriveMountPointPath(&test_profile_)
+                           .AppendASCII("foo.txt"),
+                       "text/plain", false);
+  file_urls.emplace_back("filesystem:chrome-extension://id/dir/foo.txt");
 
   std::vector<FullTaskDescriptor> tasks;
   FindAllTypesOfTasksSynchronousWrapper().Call(
@@ -865,7 +861,7 @@
   app_resources.push_back(std::move(foo_app));
   google_apis::AppList app_list;
   app_list.set_items(std::move(app_resources));
-  drive::DriveAppRegistry drive_app_registry(NULL);
+  drive::DriveAppRegistry drive_app_registry(nullptr);
   drive_app_registry.UpdateFromAppList(app_list);
 
   // Bar.app can handle ".gdoc" files.
@@ -923,11 +919,10 @@
   // should be found.
   std::vector<extensions::EntryInfo> entries;
   std::vector<GURL> file_urls;
-  entries.push_back(
-      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
-                                .AppendASCII("foo.gdoc"),
-                            "application/vnd.google-apps.document", false));
-  file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.gdoc"));
+  entries.emplace_back(drive::util::GetDriveMountPointPath(&test_profile_)
+                           .AppendASCII("foo.gdoc"),
+                       "application/vnd.google-apps.document", false);
+  file_urls.emplace_back("filesystem:chrome-extension://id/dir/foo.gdoc");
 
   std::vector<FullTaskDescriptor> tasks;
   FindAllTypesOfTasksSynchronousWrapper().Call(
@@ -1069,10 +1064,9 @@
 
   // Test case with .txt file
   std::vector<extensions::EntryInfo> txt_entries;
-  txt_entries.push_back(
-      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
-                                .AppendASCII("foo.txt"),
-                            "text/plain", false));
+  txt_entries.emplace_back(drive::util::GetDriveMountPointPath(&test_profile_)
+                               .AppendASCII("foo.txt"),
+                           "text/plain", false);
   std::vector<FullTaskDescriptor> txt_result;
   FindFileHandlerTasks(&test_profile_, txt_entries, &txt_result);
   EXPECT_EQ(4U, txt_result.size());
@@ -1091,10 +1085,9 @@
 
   // Test case with .jpg file
   std::vector<extensions::EntryInfo> jpg_entries;
-  jpg_entries.push_back(
-      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
-                                .AppendASCII("foo.jpg"),
-                            "image/jpeg", false));
+  jpg_entries.emplace_back(drive::util::GetDriveMountPointPath(&test_profile_)
+                               .AppendASCII("foo.jpg"),
+                           "image/jpeg", false);
   std::vector<FullTaskDescriptor> jpg_result;
   FindFileHandlerTasks(&test_profile_, jpg_entries, &jpg_result);
   EXPECT_EQ(3U, jpg_result.size());
@@ -1111,9 +1104,9 @@
 
   // Test case with directories.
   std::vector<extensions::EntryInfo> dir_entries;
-  dir_entries.push_back(extensions::EntryInfo(
+  dir_entries.emplace_back(
       drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII("dir"),
-      "", true));
+      "", true);
   std::vector<FullTaskDescriptor> dir_result;
   FindFileHandlerTasks(&test_profile_, dir_entries, &dir_result);
   ASSERT_EQ(1U, dir_result.size());
@@ -1199,10 +1192,9 @@
   // but only one ADD_TO that is not a generic handler will be taken into
   // account, even though there are 2 ADD_TO matches for "text/plain".
   std::vector<extensions::EntryInfo> entries;
-  entries.push_back(
-      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
-                                .AppendASCII("foo.txt"),
-                            "text/plain", false));
+  entries.emplace_back(drive::util::GetDriveMountPointPath(&test_profile_)
+                           .AppendASCII("foo.txt"),
+                       "text/plain", false);
 
   std::vector<FullTaskDescriptor> tasks;
   FindFileHandlerTasks(&test_profile_, entries, &tasks);
@@ -1226,10 +1218,9 @@
   // ADD_TO that is a good match will be taken into account, even though there
   // are 3 ADD_TO matches for "text/html".
   entries.clear();
-  entries.push_back(
-      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
-                                .AppendASCII("foo.html"),
-                            "text/html", false));
+  entries.emplace_back(drive::util::GetDriveMountPointPath(&test_profile_)
+                           .AppendASCII("foo.html"),
+                       "text/html", false);
   tasks.clear();
   FindFileHandlerTasks(&test_profile_, entries, &tasks);
 
@@ -1244,9 +1235,9 @@
   // Find app with corresponding verbs for directories.
   // Foo.app with only PACK_WITH should be found.
   entries.clear();
-  entries.push_back(extensions::EntryInfo(
+  entries.emplace_back(
       drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII("dir"),
-      "", true));
+      "", true);
   tasks.clear();
   FindFileHandlerTasks(&test_profile_, entries, &tasks);
 
diff --git a/chrome/browser/chromeos/file_manager/file_watcher.cc b/chrome/browser/chromeos/file_manager/file_watcher.cc
index 60f9a6e2..ef4a7b5 100644
--- a/chrome/browser/chromeos/file_manager/file_watcher.cc
+++ b/chrome/browser/chromeos/file_manager/file_watcher.cc
@@ -24,7 +24,7 @@
 
   std::unique_ptr<base::FilePathWatcher> watcher(new base::FilePathWatcher);
   if (!watcher->Watch(watch_path, false /* recursive */, callback))
-    return NULL;
+    return nullptr;
 
   return watcher.release();
 }
@@ -34,7 +34,7 @@
 FileWatcher::FileWatcher(const base::FilePath& virtual_path)
     : sequenced_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
           {base::MayBlock(), base::TaskPriority::USER_VISIBLE})),
-      local_file_watcher_(NULL),
+      local_file_watcher_(nullptr),
       virtual_path_(virtual_path),
       weak_ptr_factory_(this) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/chrome/browser/chromeos/file_manager/fileapi_util.cc b/chrome/browser/chromeos/file_manager/fileapi_util.cc
index 9d23921..69f1b38 100644
--- a/chrome/browser/chromeos/file_manager/fileapi_util.cc
+++ b/chrome/browser/chromeos/file_manager/fileapi_util.cc
@@ -69,7 +69,7 @@
                               const std::string& extension_id,
                               const FileDefinitionList& file_definition_list,
                               const EntryDefinitionListCallback& callback);
-  ~FileDefinitionListConverter() {}
+  ~FileDefinitionListConverter() = default;
 
  private:
   // Converts the element under the iterator to an entry. First, converts
@@ -408,13 +408,11 @@
 
 }  // namespace
 
-EntryDefinition::EntryDefinition() {
-}
+EntryDefinition::EntryDefinition() = default;
 
 EntryDefinition::EntryDefinition(const EntryDefinition& other) = default;
 
-EntryDefinition::~EntryDefinition() {
-}
+EntryDefinition::~EntryDefinition() = default;
 
 storage::FileSystemContext* GetFileSystemContextForExtensionId(
     Profile* profile,
diff --git a/chrome/browser/chromeos/file_manager/fileapi_util_unittest.cc b/chrome/browser/chromeos/file_manager/fileapi_util_unittest.cc
index 9112e322..b26b187d 100644
--- a/chrome/browser/chromeos/file_manager/fileapi_util_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/fileapi_util_unittest.cc
@@ -36,14 +36,11 @@
     Profile* profile) {
   drive::FakeDriveService* const drive_service = new drive::FakeDriveService;
   if (!drive::test_util::SetUpTestEntries(drive_service))
-    return NULL;
+    return nullptr;
 
   return new drive::DriveIntegrationService(
-      profile,
-      NULL,
-      drive_service,
-      /* default mount name */ "",
-      temp_dir,
+      profile, nullptr, drive_service,
+      /* default mount name */ "", temp_dir,
       new drive::test_util::FakeFileSystem(drive_service));
 }
 
diff --git a/chrome/browser/chromeos/file_manager/gallery_browsertest.cc b/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
index 9e46bcc1..294e458 100644
--- a/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
@@ -9,6 +9,9 @@
 template <GuestMode MODE>
 class GalleryBrowserTestBase : public FileManagerBrowserTestBase {
  public:
+  GalleryBrowserTestBase() = default;
+
+ protected:
   GuestMode GetGuestMode() const override { return MODE; }
 
   const char* GetTestCaseName() const override {
@@ -19,11 +22,12 @@
     return "gallery_test_manifest.json";
   }
 
- protected:
   void set_test_case_name(const std::string& name) { test_case_name_ = name; }
 
  private:
   std::string test_case_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(GalleryBrowserTestBase);
 };
 
 typedef GalleryBrowserTestBase<NOT_IN_GUEST_MODE> GalleryBrowserTest;
diff --git a/chrome/browser/chromeos/file_manager/open_util.cc b/chrome/browser/chromeos/file_manager/open_util.cc
index bf709f0..25fc7f2 100644
--- a/chrome/browser/chromeos/file_manager/open_util.cc
+++ b/chrome/browser/chromeos/file_manager/open_util.cc
@@ -113,7 +113,7 @@
                           const platform_util::OpenOperationCallback& callback,
                           const std::string& mime_type) {
   std::vector<extensions::EntryInfo> entries;
-  entries.push_back(extensions::EntryInfo(path, mime_type, false));
+  entries.emplace_back(path, mime_type, false);
 
   std::vector<GURL> file_urls;
   file_urls.push_back(url);
diff --git a/chrome/browser/chromeos/file_manager/path_util.cc b/chrome/browser/chromeos/file_manager/path_util.cc
index f7394be..b273f3b 100644
--- a/chrome/browser/chromeos/file_manager/path_util.cc
+++ b/chrome/browser/chromeos/file_manager/path_util.cc
@@ -109,7 +109,7 @@
       user_manager::UserManager::IsInitialized()
           ? chromeos::ProfileHelper::Get()->GetUserByProfile(
                 profile->GetOriginalProfile())
-          : NULL;
+          : nullptr;
   const std::string id = user ? "-" + user->username_hash() : "";
   return net::EscapeQueryParamValue(kDownloadsFolderName + id, false);
 }
diff --git a/chrome/browser/chromeos/file_manager/snapshot_manager.cc b/chrome/browser/chromeos/file_manager/snapshot_manager.cc
index 5ef32c0..28d201b 100644
--- a/chrome/browser/chromeos/file_manager/snapshot_manager.cc
+++ b/chrome/browser/chromeos/file_manager/snapshot_manager.cc
@@ -109,8 +109,8 @@
 SnapshotManager::FileReferenceWithSizeInfo::FileReferenceWithSizeInfo(
     const FileReferenceWithSizeInfo& other) = default;
 
-SnapshotManager::FileReferenceWithSizeInfo::~FileReferenceWithSizeInfo() {
-}
+SnapshotManager::FileReferenceWithSizeInfo::~FileReferenceWithSizeInfo() =
+    default;
 
 SnapshotManager::SnapshotManager(Profile* profile)
     : profile_(profile), weak_ptr_factory_(this) {
diff --git a/chrome/browser/chromeos/file_manager/url_util_unittest.cc b/chrome/browser/chromeos/file_manager/url_util_unittest.cc
index 16d4439e..8f7e145 100644
--- a/chrome/browser/chromeos/file_manager/url_util_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/url_util_unittest.cc
@@ -38,13 +38,11 @@
 
 TEST(FileManagerUrlUtilTest, GetFileManagerMainPageUrlWithParams_NoFileTypes) {
   const GURL url = GetFileManagerMainPageUrlWithParams(
-      ui::SelectFileDialog::SELECT_OPEN_FILE,
-      base::UTF8ToUTF16("some title"),
+      ui::SelectFileDialog::SELECT_OPEN_FILE, base::UTF8ToUTF16("some title"),
       GURL("filesystem:chrome-extension://abc/Downloads/"),
-      GURL("filesystem:chrome-extension://abc/Downloads/foo.txt"),
-      "foo.txt",
-      NULL,  // No file types
-      0,  // Hence no file type index.
+      GURL("filesystem:chrome-extension://abc/Downloads/foo.txt"), "foo.txt",
+      nullptr,  // No file types
+      0,        // Hence no file type index.
       FILE_PATH_LITERAL("txt"));
   EXPECT_EQ(extensions::kExtensionScheme, url.scheme());
   EXPECT_EQ("hhaomjibdihmijegdhdafkllkbggdgoj", url.host());
@@ -74,10 +72,10 @@
   // extensions: [["htm", "html"], ["txt"]]
   // descriptions: ["HTML", "TEXT"]
   ui::SelectFileDialog::FileTypeInfo file_types;
-  file_types.extensions.push_back(std::vector<base::FilePath::StringType>());
+  file_types.extensions.emplace_back();
   file_types.extensions[0].push_back(FILE_PATH_LITERAL("htm"));
   file_types.extensions[0].push_back(FILE_PATH_LITERAL("html"));
-  file_types.extensions.push_back(std::vector<base::FilePath::StringType>());
+  file_types.extensions.emplace_back();
   file_types.extensions[1].push_back(FILE_PATH_LITERAL("txt"));
   file_types.extension_description_overrides.push_back(
       base::UTF8ToUTF16("HTML"));
diff --git a/chrome/browser/chromeos/file_manager/video_player_browsertest.cc b/chrome/browser/chromeos/file_manager/video_player_browsertest.cc
index 318415c..008c2a8 100644
--- a/chrome/browser/chromeos/file_manager/video_player_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/video_player_browsertest.cc
@@ -11,6 +11,9 @@
 template <GuestMode MODE>
 class VideoPlayerBrowserTestBase : public FileManagerBrowserTestBase {
  public:
+  VideoPlayerBrowserTestBase() = default;
+
+ protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitch(
         chromeos::switches::kEnableVideoPlayerChromecastSupport);
@@ -28,11 +31,12 @@
     return "video_player_test_manifest.json";
   }
 
- protected:
   void set_test_case_name(const std::string& name) { test_case_name_ = name; }
 
  private:
   std::string test_case_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(VideoPlayerBrowserTestBase);
 };
 
 typedef VideoPlayerBrowserTestBase<NOT_IN_GUEST_MODE> VideoPlayerBrowserTest;
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc
index e0ae173..2a4739b 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -162,8 +162,7 @@
       watchable_(false) {
 }
 
-Volume::~Volume() {
-}
+Volume::~Volume() = default;
 
 // static
 std::unique_ptr<Volume> Volume::CreateForDrive(Profile* profile) {
@@ -342,8 +341,7 @@
   DCHECK(disk_mount_manager);
 }
 
-VolumeManager::~VolumeManager() {
-}
+VolumeManager::~VolumeManager() = default;
 
 VolumeManager* VolumeManager::Get(content::BrowserContext* context) {
   return VolumeManagerFactory::Get(context);
diff --git a/chrome/browser/chromeos/file_manager/volume_manager_factory.cc b/chrome/browser/chromeos/file_manager/volume_manager_factory.cc
index d82e2f2b5..65d0592 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager_factory.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager_factory.cc
@@ -63,7 +63,6 @@
   DependsOn(chromeos::file_system_provider::ServiceFactory::GetInstance());
 }
 
-VolumeManagerFactory::~VolumeManagerFactory() {
-}
+VolumeManagerFactory::~VolumeManagerFactory() = default;
 
 }  // namespace file_manager
diff --git a/chrome/browser/chromeos/file_manager/volume_manager_observer.h b/chrome/browser/chromeos/file_manager/volume_manager_observer.h
index 4aa1ad02..bf300c7 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager_observer.h
+++ b/chrome/browser/chromeos/file_manager/volume_manager_observer.h
@@ -17,7 +17,7 @@
 // Observer interface of volume related events.
 class VolumeManagerObserver {
  public:
-  virtual ~VolumeManagerObserver() {}
+  virtual ~VolumeManagerObserver() = default;
 
   // Fired when a new disk is added.
   virtual void OnDiskAdded(
diff --git a/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc b/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc
index ee5e2fc..117b3bf0 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc
@@ -63,8 +63,8 @@
     bool success;
   };
 
-  LoggingObserver() {}
-  ~LoggingObserver() override {}
+  LoggingObserver() = default;
+  ~LoggingObserver() override = default;
 
   const std::vector<Event>& events() const { return events_; }
 
@@ -176,13 +176,12 @@
                   extension_registry_.get())),
           volume_manager_(new VolumeManager(
               profile_.get(),
-              NULL,  // DriveIntegrationService
+              nullptr,  // DriveIntegrationService
               power_manager_client,
               disk_manager,
               file_system_provider_service_.get(),
               base::Bind(&ProfileEnvironment::GetFakeMtpStorageInfo,
-                         base::Unretained(this)))) {
-    }
+                         base::Unretained(this)))) {}
 
     Profile* profile() const { return profile_.get(); }
     VolumeManager* volume_manager() const { return volume_manager_.get(); }
@@ -203,10 +202,11 @@
   };
 
   void SetUp() override {
-    power_manager_client_.reset(new chromeos::FakePowerManagerClient);
-    disk_mount_manager_.reset(new FakeDiskMountManager);
-    main_profile_.reset(new ProfileEnvironment(power_manager_client_.get(),
-                                               disk_mount_manager_.get()));
+    power_manager_client_ =
+        std::make_unique<chromeos::FakePowerManagerClient>();
+    disk_mount_manager_ = std::make_unique<FakeDiskMountManager>();
+    main_profile_ = std::make_unique<ProfileEnvironment>(
+        power_manager_client_.get(), disk_mount_manager_.get());
   }
 
   Profile* profile() const { return main_profile_->profile(); }
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.cc b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
index d3889c6..7c8e3a85 100644
--- a/chrome/browser/chromeos/login/lock/views_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
@@ -8,7 +8,6 @@
 #include <string>
 #include <utility>
 
-#include "ash/public/interfaces/login_user_info.mojom.h"
 #include "base/bind.h"
 #include "base/i18n/time_formatting.h"
 #include "base/metrics/histogram_macros.h"
@@ -40,21 +39,6 @@
 
 namespace {
 constexpr char kLockDisplay[] = "lock";
-
-ash::mojom::FingerprintUnlockState ConvertFromFingerprintState(
-    ScreenLocker::FingerprintState state) {
-  switch (state) {
-    case ScreenLocker::FingerprintState::kRemoved:
-    case ScreenLocker::FingerprintState::kHidden:
-    case ScreenLocker::FingerprintState::kDefault:
-      return ash::mojom::FingerprintUnlockState::UNAVAILABLE;
-    case ScreenLocker::FingerprintState::kSignin:
-      return ash::mojom::FingerprintUnlockState::AUTH_SUCCESS;
-    case ScreenLocker::FingerprintState::kFailed:
-      return ash::mojom::FingerprintUnlockState::AUTH_FAILED;
-  }
-}
-
 }  // namespace
 
 ViewsScreenLocker::ViewsScreenLocker(ScreenLocker* screen_locker)
@@ -166,8 +150,7 @@
 void ViewsScreenLocker::SetFingerprintState(
     const AccountId& account_id,
     ScreenLocker::FingerprintState state) {
-  LoginScreenClient::Get()->login_screen()->SetFingerprintUnlockState(
-      account_id, ConvertFromFingerprintState(state));
+  NOTIMPLEMENTED();
 }
 
 content::WebContents* ViewsScreenLocker::GetWebContents() {
diff --git a/chrome/browser/component_updater/sw_reporter_installer_win.cc b/chrome/browser/component_updater/sw_reporter_installer_win.cc
index 818b2f74..b7129778e 100644
--- a/chrome/browser/component_updater/sw_reporter_installer_win.cc
+++ b/chrome/browser/component_updater/sw_reporter_installer_win.cc
@@ -76,6 +76,18 @@
 const base::FilePath::CharType kSwReporterExeName[] =
     FILE_PATH_LITERAL("software_reporter_tool.exe");
 
+// SwReporter is normally only registered in official builds.  However, to
+// enable testing in chromium build bots, test code can set this to true.
+#if defined(GOOGLE_CHROME_BUILD)
+bool is_sw_reporter_enabled = true;
+#else
+bool is_sw_reporter_enabled = false;
+#endif
+
+// Callback function to be called once the registration of the component
+// is complete.  This is used only in tests.
+base::OnceClosure* registration_cb_for_testing = new base::OnceClosure();
+
 void SRTHasCompleted(SRTCompleted value) {
   UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.Cleaner.HasCompleted", value,
                             SRT_COMPLETED_MAX);
@@ -460,6 +472,13 @@
 }
 
 void RegisterSwReporterComponent(ComponentUpdateService* cus) {
+  base::ScopedClosureRunner runner(std::move(*registration_cb_for_testing));
+
+  // Don't install the component if not allowed by policy.  This prevents
+  // downloads and background scans.
+  if (!is_sw_reporter_enabled || !safe_browsing::SwReporterIsAllowedByPolicy())
+    return;
+
   ReportUMAForLastCleanerRun();
 
   // Once the component is ready and browser startup is complete, run
@@ -479,7 +498,13 @@
   // Install the component.
   auto installer = base::MakeRefCounted<ComponentInstaller>(
       std::make_unique<SwReporterInstallerPolicy>(base::BindRepeating(lambda)));
-  installer->Register(cus, base::OnceClosure());
+  installer->Register(cus, runner.Release());
+}
+
+void SetRegisterSwReporterComponentCallbackForTesting(
+    base::OnceClosure registration_cb) {
+  is_sw_reporter_enabled = true;
+  *registration_cb_for_testing = std::move(registration_cb);
 }
 
 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) {
diff --git a/chrome/browser/component_updater/sw_reporter_installer_win.h b/chrome/browser/component_updater/sw_reporter_installer_win.h
index b72a5d7..923e04c 100644
--- a/chrome/browser/component_updater/sw_reporter_installer_win.h
+++ b/chrome/browser/component_updater/sw_reporter_installer_win.h
@@ -105,6 +105,11 @@
 // SwReporter. Once ready, this may trigger a periodic run of the reporter.
 void RegisterSwReporterComponent(ComponentUpdateService* cus);
 
+// Allow tests to register a function to be called when the registration
+// of the reporter component is done.
+void SetRegisterSwReporterComponentCallbackForTesting(
+    base::OnceClosure registration_cb);
+
 // Register local state preferences related to the SwReporter.
 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry);
 
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index dcd3433..e5d5d81 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -17,6 +17,7 @@
 #include "components/autofill/core/common/autofill_pref_names.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
 #include "components/browsing_data/core/pref_names.h"
+#include "components/component_updater/pref_names.h"
 #include "components/content_settings/core/common/pref_names.h"
 #include "components/drive/drive_pref_names.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
@@ -77,6 +78,11 @@
   if (pref_name == ash::prefs::kEnableAutoScreenLock)
     return true;
 #endif
+#if defined(OS_WIN)
+  // Don't allow user to change sw_reporter preferences.
+  if (pref_name == prefs::kSwReporterEnabled)
+    return true;
+#endif
   return false;
 }
 
@@ -483,6 +489,12 @@
   (*s_whitelist)[::prefs::kMediaRouterMediaRemotingEnabled] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
 
+#if defined(OS_WIN)
+  // SwReporter settings.
+  (*s_whitelist)[::prefs::kSwReporterEnabled] =
+      settings_api::PrefType::PREF_TYPE_BOOLEAN;
+#endif
+
   return *s_whitelist;
 }
 
diff --git a/chrome/browser/extensions/extension_protocols_unittest.cc b/chrome/browser/extensions/extension_protocols_unittest.cc
index 47eb4a1..167d7b9 100644
--- a/chrome/browser/extensions/extension_protocols_unittest.cc
+++ b/chrome/browser/extensions/extension_protocols_unittest.cc
@@ -35,6 +35,7 @@
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_protocols.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
 #include "extensions/browser/info_map.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
@@ -196,7 +197,6 @@
     testing::Test::SetUp();
     testing_profile_ = TestingProfile::Builder().Build();
     contents_ = CreateTestWebContents();
-    extension_info_map_ = new InfoMap();
     old_factory_ = resource_context_.GetRequestContext()->job_factory();
 
     // Set up content verification.
@@ -207,7 +207,7 @@
     content_verifier_ = new ContentVerifier(
         browser_context(),
         std::make_unique<ChromeContentVerifierDelegate>(browser_context()));
-    extension_info_map_->SetContentVerifier(content_verifier_.get());
+    info_map()->SetContentVerifier(content_verifier_.get());
   }
 
   void TearDown() override {
@@ -220,13 +220,12 @@
     switch (request_handler()) {
       case RequestHandlerType::kURLLoader:
         loader_factory_ = extensions::CreateExtensionNavigationURLLoaderFactory(
-            main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(),
-            extension_info_map_.get());
+            browser_context(), false);
         break;
       case RequestHandlerType::kURLRequest:
         job_factory_.SetProtocolHandler(
-            kExtensionScheme, CreateExtensionProtocolHandler(
-                                  is_incognito, extension_info_map_.get()));
+            kExtensionScheme,
+            CreateExtensionProtocolHandler(is_incognito, info_map()));
         resource_context_.GetRequestContext()->set_job_factory(&job_factory_);
         break;
     }
@@ -247,9 +246,8 @@
   void AddExtension(const scoped_refptr<const Extension>& extension,
                     bool incognito_enabled,
                     bool notifications_disabled) {
-    extension_info_map_->AddExtension(extension.get(), base::Time::Now(),
-                                      incognito_enabled,
-                                      notifications_disabled);
+    info_map()->AddExtension(extension.get(), base::Time::Now(),
+                             incognito_enabled, notifications_disabled);
     if (request_handler() == RequestHandlerType::kURLLoader) {
       EXPECT_TRUE(extension_registry()->AddEnabled(extension));
       ExtensionPrefs::Get(browser_context())
@@ -259,7 +257,7 @@
 
   void RemoveExtension(const scoped_refptr<const Extension>& extension,
                        const UnloadedExtensionReason reason) {
-    extension_info_map_->RemoveExtension(extension->id(), reason);
+    info_map()->RemoveExtension(extension->id(), reason);
     if (request_handler() == RequestHandlerType::kURLLoader) {
       EXPECT_TRUE(extension_registry()->RemoveEnabled(extension->id()));
       if (reason == UnloadedExtensionReason::DISABLE)
@@ -269,10 +267,10 @@
 
   // Helper method to create a URL request/loader, call RequestOrLoad on it, and
   // return the result. If |extension| hasn't already been added to
-  // |extension_info_map_|, this will add it.
+  // info_map(), this will add it.
   GetResult DoRequestOrLoad(const scoped_refptr<Extension> extension,
                             const std::string& relative_path) {
-    if (!extension_info_map_->extensions().Contains(extension->id())) {
+    if (!info_map()->extensions().Contains(extension->id())) {
       AddExtension(extension.get(),
                    /*incognito_enabled=*/false,
                    /*notifications_disabled=*/false);
@@ -285,6 +283,10 @@
     return ExtensionRegistry::Get(browser_context());
   }
 
+  InfoMap* info_map() {
+    return ExtensionSystem::Get(browser_context())->info_map();
+  }
+
   content::BrowserContext* browser_context() { return testing_profile_.get(); }
 
  protected:
@@ -352,7 +354,6 @@
   std::unique_ptr<TestingProfile> testing_profile_;
   net::TestDelegate test_delegate_;
   std::unique_ptr<content::WebContents> contents_;
-  scoped_refptr<InfoMap> extension_info_map_;
 };
 
 // Tests that making a chrome-extension request in an incognito context is
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index e6ba0b0..de88ce5 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -1109,9 +1109,6 @@
 
 void ExtensionService::OnAllExternalProvidersReady() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  base::TimeDelta elapsed = base::Time::Now() - profile_->GetStartTime();
-  UMA_HISTOGRAM_TIMES("Extension.ExternalProvidersReadyAfter", elapsed);
-
   // Install any pending extensions.
   if (update_once_all_providers_are_ready_ && updater()) {
     update_once_all_providers_are_ready_ = false;
diff --git a/chrome/browser/external_protocol/external_protocol_handler.cc b/chrome/browser/external_protocol/external_protocol_handler.cc
index 681b280..3779df9 100644
--- a/chrome/browser/external_protocol/external_protocol_handler.cc
+++ b/chrome/browser/external_protocol/external_protocol_handler.cc
@@ -90,16 +90,20 @@
 
 void LaunchUrlWithoutSecurityCheckWithDelegate(
     const GURL& url,
-    int render_process_host_id,
-    int render_view_routing_id,
+    content::WebContents* web_contents,
     ExternalProtocolHandler::Delegate* delegate) {
-  content::WebContents* web_contents = tab_util::GetWebContentsByID(
-      render_process_host_id, render_view_routing_id);
   if (delegate) {
     delegate->LaunchUrlWithoutSecurityCheck(url, web_contents);
     return;
   }
-  ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(url, web_contents);
+
+  // |web_contents| is only passed in to find browser context. Do not assume
+  // that the external protocol request came from the main frame.
+  if (!web_contents)
+    return;
+
+  platform_util::OpenExternal(
+      Profile::FromBrowserContext(web_contents->GetBrowserContext()), url);
 }
 
 // When we are about to launch a URL with the default OS level application, we
@@ -137,8 +141,10 @@
     return;
   }
 
-  LaunchUrlWithoutSecurityCheckWithDelegate(escaped_url, render_process_host_id,
-                                            render_view_routing_id, delegate);
+  content::WebContents* web_contents = tab_util::GetWebContentsByID(
+      render_process_host_id, render_view_routing_id);
+  LaunchUrlWithoutSecurityCheckWithDelegate(escaped_url, web_contents,
+                                            delegate);
 }
 
 }  // namespace
@@ -267,13 +273,8 @@
 void ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(
     const GURL& url,
     content::WebContents* web_contents) {
-  // |web_contents| is only passed in to find browser context. Do not assume
-  // that the external protocol request came from the main frame.
-  if (!web_contents)
-    return;
-
-  platform_util::OpenExternal(
-      Profile::FromBrowserContext(web_contents->GetBrowserContext()), url);
+  LaunchUrlWithoutSecurityCheckWithDelegate(
+      url, web_contents, g_external_protocol_handler_delegate);
 }
 
 // static
diff --git a/chrome/browser/google/chrome_google_url_tracker_client.cc b/chrome/browser/google/chrome_google_url_tracker_client.cc
index 60b1e7b..360869b 100644
--- a/chrome/browser/google/chrome_google_url_tracker_client.cc
+++ b/chrome/browser/google/chrome_google_url_tracker_client.cc
@@ -7,6 +7,8 @@
 #include "base/command_line.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
+#include "content/public/browser/storage_partition.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
 
 ChromeGoogleURLTrackerClient::ChromeGoogleURLTrackerClient(Profile* profile)
     : profile_(profile) {
@@ -24,7 +26,9 @@
   return profile_->GetPrefs();
 }
 
-net::URLRequestContextGetter*
-ChromeGoogleURLTrackerClient::GetRequestContext() {
-  return profile_->GetRequestContext();
+network::mojom::URLLoaderFactory*
+ChromeGoogleURLTrackerClient::GetURLLoaderFactory() {
+  return content::BrowserContext::GetDefaultStoragePartition(profile_)
+      ->GetURLLoaderFactoryForBrowserProcess()
+      .get();
 }
diff --git a/chrome/browser/google/chrome_google_url_tracker_client.h b/chrome/browser/google/chrome_google_url_tracker_client.h
index 0d826ae..74b0565 100644
--- a/chrome/browser/google/chrome_google_url_tracker_client.h
+++ b/chrome/browser/google/chrome_google_url_tracker_client.h
@@ -18,7 +18,7 @@
   // GoogleURLTrackerClient:
   bool IsBackgroundNetworkingEnabled() override;
   PrefService* GetPrefs() override;
-  net::URLRequestContextGetter* GetRequestContext() override;
+  network::mojom::URLLoaderFactory* GetURLLoaderFactory() override;
 
  private:
   Profile* profile_;
diff --git a/chrome/browser/net/errorpage_browsertest.cc b/chrome/browser/net/errorpage_browsertest.cc
index a898c782..7a64c50 100644
--- a/chrome/browser/net/errorpage_browsertest.cc
+++ b/chrome/browser/net/errorpage_browsertest.cc
@@ -1030,6 +1030,8 @@
         std::make_unique<content::URLLoaderInterceptor>(base::BindRepeating(
             [](int32_t requests_to_fail, int32_t* requests, int32_t* failures,
                content::URLLoaderInterceptor::RequestParams* params) {
+              if (params->url_request.url.path() == "/searchdomaincheck")
+                return false;
               if (params->url_request.url.path() == "/favicon.ico")
                 return false;
               (*requests)++;
diff --git a/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc b/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc
index 1773f332..c63145a 100644
--- a/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc
+++ b/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc
@@ -1007,132 +1007,3 @@
   // notification should be shown without an image.
   EXPECT_TRUE(notifications[0].image().IsEmpty());
 }
-
-class PlatformNotificationServiceMojoEnabledBrowserTest
-    : public PlatformNotificationServiceBrowserTest {
- public:
-  // InProcessBrowserTest overrides.
-  void SetUpInProcessBrowserTestFixture() override {
-    scoped_feature_list_.InitWithFeatures({features::kNotificationsWithMojo},
-                                          {});
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceMojoEnabledBrowserTest,
-                       DisplayPersistentNotificationWithPermission) {
-  RequestAndAcceptPermission();
-
-  std::string script_result;
-  ASSERT_TRUE(RunScript("DisplayPersistentNotification('action_none')",
-                        &script_result));
-  EXPECT_EQ("ok", script_result);
-
-  std::vector<message_center::Notification> notifications =
-      GetDisplayedNotifications(true /* is_persistent */);
-  ASSERT_EQ(1u, notifications.size());
-}
-
-IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceMojoEnabledBrowserTest,
-                       PersistentNotificationServiceWorkerScope) {
-  RequestAndAcceptPermission();
-
-  // Creates a simple notification.
-  std::string script_result;
-  ASSERT_TRUE(RunScript("DisplayPersistentNotification()", &script_result));
-
-  std::vector<message_center::Notification> notifications =
-      GetDisplayedNotifications(true /* is_persistent */);
-  ASSERT_EQ(1u, notifications.size());
-
-  EXPECT_EQ(
-      TestPageUrl(),
-      PersistentNotificationMetadata::From(
-          display_service_tester_->GetMetadataForNotification(notifications[0]))
-          ->service_worker_scope);
-}
-
-IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceMojoEnabledBrowserTest,
-                       GetDisplayedNotifications) {
-  RequestAndAcceptPermission();
-
-  std::string script_result;
-  std::string script_message;
-
-  ASSERT_TRUE(RunScript("DisplayNonPersistentNotification('NonPersistent')",
-                        &script_result));
-  EXPECT_EQ("ok", script_result);
-  ASSERT_TRUE(RunScript("DisplayPersistentNotification('PersistentI')",
-                        &script_result));
-  EXPECT_EQ("ok", script_result);
-  ASSERT_TRUE(RunScript("DisplayPersistentNotification('PersistentII')",
-                        &script_result));
-  EXPECT_EQ("ok", script_result);
-
-  // Only the persistent ones should show.
-  ASSERT_TRUE(RunScript("GetDisplayedNotifications()", &script_result));
-  EXPECT_EQ("ok", script_result);
-
-  ASSERT_TRUE(RunScript("GetMessageFromWorker()", &script_message));
-
-  std::vector<std::string> notification_ids = base::SplitString(
-      script_message, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
-
-  ASSERT_EQ(2u, notification_ids.size());
-
-  const std::string first_id = notification_ids[0];
-
-  std::vector<message_center::Notification> notifications =
-      GetDisplayedNotifications(true /* is_persistent */);
-  ASSERT_EQ(notification_ids.size(), notifications.size());
-
-  // Now remove one of the notifications straight from the ui manager
-  // without going through the database.
-  const message_center::Notification& notification = notifications[1];
-
-  // p# is the prefix for persistent notifications. See
-  //  content/browser/notifications/notification_id_generator.{h,cc} for details
-  ASSERT_TRUE(
-      base::StartsWith(notification.id(), "p#", base::CompareCase::SENSITIVE));
-
-  display_service_tester_->RemoveNotification(
-      NotificationHandler::Type::WEB_PERSISTENT, notification.id(),
-      false /* by_user */, true /* silent */);
-
-  ASSERT_TRUE(RunScript("GetDisplayedNotifications()", &script_result));
-  EXPECT_EQ("ok", script_result);
-
-  ASSERT_TRUE(RunScript("GetMessageFromWorker()", &script_message));
-  notification_ids = base::SplitString(
-      script_message, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
-
-  // The list of displayed notification Ids should have been updated.
-  ASSERT_EQ(1u, notification_ids.size());
-  ASSERT_EQ(notification_ids[0], first_id);
-}
-
-IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceMojoEnabledBrowserTest,
-                       CloseDisplayedPersistentNotification) {
-  ASSERT_NO_FATAL_FAILURE(GrantNotificationPermissionForTest());
-
-  std::string script_result;
-  ASSERT_TRUE(RunScript("DisplayPersistentNotification('action_close')",
-                        &script_result));
-  EXPECT_EQ("ok", script_result);
-
-  std::vector<message_center::Notification> notifications =
-      GetDisplayedNotifications(true /* is_persistent */);
-  ASSERT_EQ(1u, notifications.size());
-
-  display_service_tester_->SimulateClick(
-      NotificationHandler::Type::WEB_PERSISTENT, notifications[0].id(),
-      base::nullopt /* action_index */, base::nullopt /* reply */);
-
-  ASSERT_TRUE(RunScript("GetMessageFromWorker()", &script_result));
-  EXPECT_EQ("action_close", script_result);
-
-  notifications = GetDisplayedNotifications(true /* is_persistent */);
-  ASSERT_EQ(0u, notifications.size());
-}
diff --git a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
index 8253dc0c..80072a15 100644
--- a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
+++ b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
@@ -29,6 +29,7 @@
           WebFeature::kPaymentRequestShowWithoutGesture,
           WebFeature::kHTMLImports, WebFeature::kHTMLImportsHasStyleSheets,
           WebFeature::kElementCreateShadowRoot,
+          WebFeature::kPaymentRequestInvalidCurrencyCode,
       }));
   return opt_in_features.count(feature);
 }
diff --git a/chrome/browser/permissions/permission_context_base.cc b/chrome/browser/permissions/permission_context_base.cc
index b3b771e..7a916767 100644
--- a/chrome/browser/permissions/permission_context_base.cc
+++ b/chrome/browser/permissions/permission_context_base.cc
@@ -27,6 +27,7 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
+#include "components/content_settings/core/browser/content_settings_registry.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/prefs/pref_service.h"
 #include "components/variations/variations_associated_data.h"
@@ -252,6 +253,10 @@
 
 void PermissionContextBase::ResetPermission(const GURL& requesting_origin,
                                             const GURL& embedding_origin) {
+  if (!content_settings::ContentSettingsRegistry::GetInstance()->Get(
+          content_settings_type_)) {
+    return;
+  }
   HostContentSettingsMapFactory::GetForProfile(profile_)
       ->SetContentSettingDefaultScope(requesting_origin, embedding_origin,
                                       content_settings_type_, std::string(),
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index 79d9f42..8883982 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -23,6 +23,7 @@
         "media_router:closure_compile",
         "offline_pages:closure_compile",
         "pdf:closure_compile",
+        "print_preview:closure_compile",
         "settings:closure_compile",
         "signin/dice_sync_confirmation:closure_compile",
         "webapks:closure_compile",
diff --git a/chrome/browser/resources/pdf/compiled_resources2.gyp b/chrome/browser/resources/pdf/compiled_resources2.gyp
deleted file mode 100644
index bbeee80..0000000
--- a/chrome/browser/resources/pdf/compiled_resources2.gyp
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  'targets': [
-    {
-      # TODO(calamity): Remove once print_preview no longer depends on this.
-      'target_name': 'pdf_scripting_api',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-  ],
-}
diff --git a/chrome/browser/resources/print_preview/BUILD.gn b/chrome/browser/resources/print_preview/BUILD.gn
index 0454c79..e36e456 100644
--- a/chrome/browser/resources/print_preview/BUILD.gn
+++ b/chrome/browser/resources/print_preview/BUILD.gn
@@ -1,46 +1,206 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
 import("../optimize_webui.gni")
 import("//tools/grit/grit_rule.gni")
 import("//chrome/common/features.gni")
 
-print_preview_pak_file = "print_preview_resources.pak"
-unpak_folder = "print_preview_resources.unpak"
+if (optimize_webui) {
+  print_preview_pak_file = "print_preview_resources.pak"
+  unpak_folder = "print_preview_resources.unpak"
 
-optimize_webui("build") {
-  host = "print"
-  html_in_files = [ "print_preview_new.html" ]
-  html_out_files = [ "vulcanized.html" ]
-  insert_in_head = "<base href=\"chrome://print\">"
-  input = rebase_path("$target_gen_dir/$unpak_folder", root_build_dir)
-  js_out_files = [ "crisper.js" ]
+  optimize_webui("build") {
+    host = "print"
+    html_in_files = [ "print_preview_new.html" ]
+    html_out_files = [ "vulcanized.html" ]
+    insert_in_head = "<base href=\"chrome://print\">"
+    input = rebase_path("$target_gen_dir/$unpak_folder", root_build_dir)
+    js_out_files = [ "crisper.js" ]
 
-  excludes = [ "pdf/pdf_scripting_api.js" ]
+    excludes = [ "pdf/pdf_scripting_api.js" ]
 
+    deps = [
+      ":unpak",
+    ]
+  }
+
+  unpak("unpak") {
+    pak_file = print_preview_pak_file
+    out_folder = unpak_folder
+
+    deps = [
+      ":flattened_resources",
+    ]
+  }
+
+  grit("flattened_resources") {
+    source = "print_preview_resources.grd"
+
+    # The .grd contains references to generated files.
+    source_is_generated = true
+
+    defines = chrome_grit_defines
+    outputs = [
+      "grit/print_preview_resources.h",
+      "grit/print_preview_resources_map.cc",
+      "grit/print_preview_resources_map.h",
+      print_preview_pak_file,
+    ]
+    output_dir = "$root_gen_dir/chrome/browser/resources/print_preview"
+  }
+}
+
+group("closure_compile") {
   deps = [
-    ":unpak",
+    ":print_preview_resources",
+    "data:closure_compile",
+    "new:closure_compile",
   ]
 }
 
-unpak("unpak") {
-  pak_file = print_preview_pak_file
-  out_folder = unpak_folder
-
+js_type_check("print_preview_resources") {
   deps = [
-    ":flattened_resources",
+    ":cloud_print_interface",
+    ":metrics",
+    ":native_layer",
+    ":print_preview",
+    ":print_preview_utils",
   ]
 }
 
-grit("flattened_resources") {
-  source = "print_preview_resources.grd"
-
-  # The .grd contains references to generated files.
-  source_is_generated = true
-
-  defines = chrome_grit_defines
-  outputs = [
-    "grit/print_preview_resources.h",
-    "grit/print_preview_resources_map.cc",
-    "grit/print_preview_resources_map.h",
-    print_preview_pak_file,
+js_library("print_preview") {
+  deps = [
+    "../pdf:pdf_scripting_api",
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js:event_tracker",
+    "//ui/webui/resources/js:load_time_data",
+    "//ui/webui/resources/js:promise_resolver",
+    "//ui/webui/resources/js:util",
+    "//ui/webui/resources/js:webui_listener_tracker",
+    "//ui/webui/resources/js/cr:event_target",
+    "//ui/webui/resources/js/cr:ui",
+    "//ui/webui/resources/js/cr/ui:focus_manager",
+    "//ui/webui/resources/js/cr/ui:focus_outline_manager",
+    "//ui/webui/resources/js/cr/ui:node_utils",
   ]
-  output_dir = "$root_gen_dir/chrome/browser/resources/print_preview"
+
+  sources = [
+    "cloud_print_interface.js",
+    "common/overlay.js",
+    "common/search_box.js",
+    "common/search_bubble.js",
+    "component.js",
+    "data/app_state.js",
+    "data/capabilities_holder.js",
+    "data/cloud_parsers.js",
+    "data/coordinate2d.js",
+    "data/destination.js",
+    "data/destination_match.js",
+    "data/destination_store.js",
+    "data/document_info.js",
+    "data/invitation.js",
+    "data/invitation_store.js",
+    "data/local_parsers.js",
+    "data/margins.js",
+    "data/measurement_system.js",
+    "data/page_number_set.js",
+    "data/print_ticket_store.js",
+    "data/printable_area.js",
+    "data/size.js",
+    "data/ticket_items/collate.js",
+    "data/ticket_items/color.js",
+    "data/ticket_items/copies.js",
+    "data/ticket_items/css_background.js",
+    "data/ticket_items/custom_margins.js",
+    "data/ticket_items/dpi.js",
+    "data/ticket_items/duplex.js",
+    "data/ticket_items/fit_to_page.js",
+    "data/ticket_items/header_footer.js",
+    "data/ticket_items/landscape.js",
+    "data/ticket_items/margins_type.js",
+    "data/ticket_items/media_size.js",
+    "data/ticket_items/page_range.js",
+    "data/ticket_items/rasterize.js",
+    "data/ticket_items/scaling.js",
+    "data/ticket_items/selection_only.js",
+    "data/ticket_items/ticket_item.js",
+    "data/ticket_items/vendor_items.js",
+    "data/user_info.js",
+    "metrics.js",
+    "native_layer.js",
+    "preview_generator.js",
+    "previewarea/margin_control.js",
+    "previewarea/margin_control_container.js",
+    "previewarea/preview_area.js",
+    "print_header.js",
+    "print_preview.js",
+    "print_preview_animations.js",
+    "print_preview_focus_manager.js",
+    "print_preview_utils.js",
+    "search/destination_list.js",
+    "search/destination_list_item.js",
+    "search/destination_search.js",
+    "search/provisional_destination_resolver.js",
+    "search/recent_destination_list.js",
+    "settings/advanced_options_settings.js",
+    "settings/advanced_settings/advanced_settings.js",
+    "settings/advanced_settings/advanced_settings_item.js",
+    "settings/color_settings.js",
+    "settings/copies_settings.js",
+    "settings/destination_settings.js",
+    "settings/dpi_settings.js",
+    "settings/layout_settings.js",
+    "settings/margin_settings.js",
+    "settings/media_size_settings.js",
+    "settings/more_settings.js",
+    "settings/other_options_settings.js",
+    "settings/page_settings.js",
+    "settings/scaling_settings.js",
+    "settings/settings_section.js",
+    "settings/settings_section_select.js",
+  ]
+
+  externs_list = [ "$externs_path/chrome_send.js" ]
+}
+
+js_library("print_preview_utils") {
+  deps = [
+    "data:coordinate2d",
+    "data:size",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("metrics") {
+  deps = [
+    ":native_layer",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("component") {
+}
+js_library("print_preview_focus_manager") {
+}
+
+js_library("cloud_print_interface") {
+  deps = [
+    ":native_layer",
+    "data:cloud_parsers",
+    "data:destination",
+    "data:document_info",
+    "data:invitation",
+    "data:user_info",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("native_layer") {
+  deps = [
+    "data:destination",
+    "data:measurement_system",
+    "//ui/webui/resources/js:cr",
+  ]
 }
diff --git a/chrome/browser/resources/print_preview/compiled_resources2.gyp b/chrome/browser/resources/print_preview/compiled_resources2.gyp
deleted file mode 100644
index 311e09e..0000000
--- a/chrome/browser/resources/print_preview/compiled_resources2.gyp
+++ /dev/null
@@ -1,69 +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.
-{
-  'targets': [
-    {
-      'target_name': 'print_preview',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:event_tracker',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:webui_listener_tracker',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:promise_resolver',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
-        '<(DEPTH)/ui/webui/resources/js/cr/compiled_resources2.gyp:event_target',
-        '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:focus_manager',
-        '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:focus_outline_manager',
-        '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:node_utils',
-        '<(DEPTH)/ui/webui/resources/js/cr/compiled_resources2.gyp:ui',
-        '<(EXTERNS_GYP):chrome_send',
-      ],
-      'variables': {
-        'extra_inputs': [
-          '<!@(python <(CLOSURE_DIR)/build/get_includes.py print_preview.js)',
-        ],
-      },
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'print_preview_utils',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        'data/compiled_resources2.gyp:size',
-        'data/compiled_resources2.gyp:coordinate2d'
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'metrics',
-      'dependencies': [
-        'native_layer',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'cloud_print_interface',
-      'dependencies': [
-        'native_layer',
-        'data/compiled_resources2.gyp:cloud_parsers',
-        'data/compiled_resources2.gyp:destination',
-        'data/compiled_resources2.gyp:document_info',
-        'data/compiled_resources2.gyp:invitation',
-        'data/compiled_resources2.gyp:user_info',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'native_layer',
-      'dependencies': [
-        'data/compiled_resources2.gyp:destination',
-        'data/compiled_resources2.gyp:measurement_system',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-  ],
-}
diff --git a/chrome/browser/resources/print_preview/component.js b/chrome/browser/resources/print_preview/component.js
index 0022784..1f69a93 100644
--- a/chrome/browser/resources/print_preview/component.js
+++ b/chrome/browser/resources/print_preview/component.js
@@ -15,7 +15,7 @@
 
     /**
      * Component's HTML element.
-     * @private {Element}
+     * @protected {Element}
      */
     this.element_ = null;
 
@@ -23,7 +23,7 @@
 
     /**
      * Component's event tracker.
-     * @private {!EventTracker}
+     * @protected {!EventTracker}
      */
     this.tracker_ = new EventTracker();
 
diff --git a/chrome/browser/resources/print_preview/data/BUILD.gn b/chrome/browser/resources/print_preview/data/BUILD.gn
new file mode 100644
index 0000000..a93e13c
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/BUILD.gn
@@ -0,0 +1,139 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+  deps = [
+    ":cloud_parsers",
+    ":coordinate2d",
+    ":destination",
+    ":destination_match",
+    ":destination_store",
+    ":document_info",
+    ":invitation",
+    ":invitation_store",
+    ":local_parsers",
+    ":margins",
+    ":measurement_system",
+    ":printable_area",
+    ":size",
+    ":user_info",
+  ]
+}
+
+js_library("destination_store") {
+  deps = [
+    ":destination",
+    ":destination_match",
+    ":local_parsers",
+    ":user_info",
+    "..:cloud_print_interface",
+    "..:metrics",
+    "..:native_layer",
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js:event_tracker",
+    "//ui/webui/resources/js:webui_listener_tracker",
+    "//ui/webui/resources/js/cr:event_target",
+  ]
+}
+
+js_library("invitation_store") {
+  deps = [
+    ":invitation",
+    ":user_info",
+    "..:cloud_print_interface",
+    "//ui/webui/resources/js:event_tracker",
+    "//ui/webui/resources/js/cr:event_target",
+  ]
+}
+
+js_library("local_parsers") {
+  deps = [
+    ":destination",
+    "..:native_layer",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("destination_match") {
+  deps = [
+    ":destination",
+    "..:native_layer",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("cloud_parsers") {
+  deps = [
+    ":destination",
+    ":invitation",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("invitation") {
+  deps = [
+    ":destination",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("destination") {
+  deps = [
+    "..:print_preview_utils",
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js:load_time_data",
+  ]
+}
+
+js_library("document_info") {
+  deps = [
+    ":coordinate2d",
+    ":margins",
+    ":printable_area",
+    ":size",
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js/cr:event_target",
+  ]
+}
+
+js_library("margins") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("measurement_system") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("printable_area") {
+  deps = [
+    ":coordinate2d",
+    ":size",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("size") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("coordinate2d") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("user_info") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js/cr:event_target",
+  ]
+}
diff --git a/chrome/browser/resources/print_preview/data/compiled_resources2.gyp b/chrome/browser/resources/print_preview/data/compiled_resources2.gyp
deleted file mode 100644
index db082079..0000000
--- a/chrome/browser/resources/print_preview/data/compiled_resources2.gyp
+++ /dev/null
@@ -1,136 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-{
-  'targets': [
-    {
-      'target_name': 'destination_store',
-      'dependencies': [
-        'destination',
-        'destination_match',
-        'local_parsers',
-        'user_info',
-        '../compiled_resources2.gyp:cloud_print_interface',
-        '../compiled_resources2.gyp:metrics',
-        '../compiled_resources2.gyp:native_layer',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:event_tracker',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:webui_listener_tracker',
-        '<(DEPTH)/ui/webui/resources/js/cr/compiled_resources2.gyp:event_target',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'invitation_store',
-      'dependencies': [
-        'invitation',
-        'user_info',
-        '../compiled_resources2.gyp:cloud_print_interface',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:event_tracker',
-        '<(DEPTH)/ui/webui/resources/js/cr/compiled_resources2.gyp:event_target',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'local_parsers',
-      'dependencies': [
-        'destination',
-        '../compiled_resources2.gyp:native_layer',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'destination_match',
-      'dependencies': [
-        'destination',
-        '../compiled_resources2.gyp:native_layer',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'cloud_parsers',
-      'dependencies': [
-        'destination',
-        'invitation',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'invitation',
-      'dependencies': [
-        'destination',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'destination',
-      'dependencies': [
-        '../compiled_resources2.gyp:print_preview_utils',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'document_info',
-      'dependencies': [
-        'margins',
-        'size',
-        'coordinate2d',
-        'printable_area',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/ui/webui/resources/js/cr/compiled_resources2.gyp:event_target',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'margins',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'measurement_system',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'printable_area',
-      'dependencies': [
-        'size',
-        'coordinate2d',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'size',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'coordinate2d',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'user_info',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/ui/webui/resources/js/cr/compiled_resources2.gyp:event_target',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-  ]
-}
diff --git a/chrome/browser/resources/print_preview/data/destination_store.js b/chrome/browser/resources/print_preview/data/destination_store.js
index 2a39d45..b7a3a51 100644
--- a/chrome/browser/resources/print_preview/data/destination_store.js
+++ b/chrome/browser/resources/print_preview/data/destination_store.js
@@ -1008,11 +1008,11 @@
      */
     updateDestination_(destination) {
       assert(destination.constructor !== Array, 'Single printer expected');
-      destination.capabilities_ =
-          localizeCapabilities(assert(destination.capabilities_));
+      destination.capabilities =
+          localizeCapabilities(assert(destination.capabilities));
       if (print_preview.originToType(destination.origin) !==
           print_preview.PrinterType.LOCAL_PRINTER) {
-        destination.capabilities_ = sortMediaSizes(destination.capabilities_);
+        destination.capabilities = sortMediaSizes(destination.capabilities);
       }
       const existingDestination =
           this.destinationMap_[this.getKey_(destination)];
diff --git a/chrome/browser/resources/print_preview/data/ticket_items/dpi.js b/chrome/browser/resources/print_preview/data/ticket_items/dpi.js
index 60c401a..0e71b32 100644
--- a/chrome/browser/resources/print_preview/data/ticket_items/dpi.js
+++ b/chrome/browser/resources/print_preview/data/ticket_items/dpi.js
@@ -21,7 +21,7 @@
     wouldValueBeValid(value) {
       if (!this.isCapabilityAvailable())
         return false;
-      return this.capability.option.some(function(option) {
+      return this.capability().option.some(function(option) {
         return option.horizontal_dpi == value.horizontal_dpi &&
             option.vertical_dpi == value.vertical_dpi &&
             option.vendor_id == value.vendor_id;
@@ -30,8 +30,8 @@
 
     /** @override */
     isCapabilityAvailable() {
-      return !!this.capability && !!this.capability.option &&
-          this.capability.option.length > 1;
+      return !!this.capability() && !!this.capability().option &&
+          this.capability().option.length > 1;
     }
 
     /** @override */
@@ -43,7 +43,7 @@
     }
 
     /** @return {Object} DPI capability of the selected destination. */
-    get capability() {
+    capability() {
       const destination = this.getSelectedDestInternal();
       return (destination && destination.capabilities &&
               destination.capabilities.printer &&
@@ -53,7 +53,7 @@
 
     /** @override */
     getDefaultValueInternal() {
-      const defaultOptions = this.capability.option.filter(function(option) {
+      const defaultOptions = this.capability().option.filter(function(option) {
         return option.is_default;
       });
       return defaultOptions.length > 0 ? defaultOptions[0] : null;
diff --git a/chrome/browser/resources/print_preview/data/ticket_items/media_size.js b/chrome/browser/resources/print_preview/data/ticket_items/media_size.js
index 6302e0b4..e8e794a8 100644
--- a/chrome/browser/resources/print_preview/data/ticket_items/media_size.js
+++ b/chrome/browser/resources/print_preview/data/ticket_items/media_size.js
@@ -44,7 +44,7 @@
       if (!this.isCapabilityAvailable()) {
         return false;
       }
-      return this.capability.option.some(function(option) {
+      return this.capability().option.some(function(option) {
         return option.width_microns == value.width_microns &&
             option.height_microns == value.height_microns &&
             option.is_continuous_feed == value.is_continuous_feed &&
@@ -60,7 +60,7 @@
           this.getSelectedDestInternal() &&
           this.getSelectedDestInternal().id ==
               print_preview.Destination.GooglePromotedId.SAVE_AS_PDF;
-      return !knownSizeToSaveAsPdf && !!this.capability;
+      return !knownSizeToSaveAsPdf && !!this.capability();
     }
 
     /** @override */
@@ -73,7 +73,7 @@
     }
 
     /** @return {Object} Media size capability of the selected destination. */
-    get capability() {
+    capability() {
       const destination = this.getSelectedDestInternal();
       return (destination && destination.capabilities &&
               destination.capabilities.printer &&
@@ -83,7 +83,7 @@
 
     /** @override */
     getDefaultValueInternal() {
-      const defaultOptions = this.capability.option.filter(function(option) {
+      const defaultOptions = this.capability().option.filter(function(option) {
         return option.is_default;
       });
       return defaultOptions.length > 0 ? defaultOptions[0] : null;
diff --git a/chrome/browser/resources/print_preview/new/BUILD.gn b/chrome/browser/resources/print_preview/new/BUILD.gn
new file mode 100644
index 0000000..b88cd988
--- /dev/null
+++ b/chrome/browser/resources/print_preview/new/BUILD.gn
@@ -0,0 +1,369 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+  deps = [
+    ":advanced_options_settings",
+    ":advanced_settings_dialog",
+    ":advanced_settings_item",
+    ":app",
+    ":color_settings",
+    ":copies_settings",
+    ":destination_dialog",
+    ":destination_list",
+    ":destination_list_item",
+    ":destination_settings",
+    ":dpi_settings",
+    ":header",
+    ":highlight_utils",
+    ":input_behavior",
+    ":layout_settings",
+    ":link_container",
+    ":margin_control",
+    ":margin_control_container",
+    ":margins_settings",
+    ":media_size_settings",
+    ":model",
+    ":more_settings",
+    ":number_settings_section",
+    ":other_options_settings",
+    ":pages_settings",
+    ":preview_area",
+    ":print_preview_search_box",
+    ":provisional_destination_resolver",
+    ":scaling_settings",
+    ":settings_behavior",
+    ":settings_section_behavior",
+    ":settings_select",
+    ":state",
+  ]
+}
+
+js_library("app") {
+  deps = [
+    ":advanced_options_settings",
+    ":color_settings",
+    ":copies_settings",
+    ":destination_settings",
+    ":dpi_settings",
+    ":header",
+    ":layout_settings",
+    ":link_container",
+    ":margins_settings",
+    ":media_size_settings",
+    ":model",
+    ":more_settings",
+    ":other_options_settings",
+    ":pages_settings",
+    ":preview_area",
+    ":scaling_settings",
+    ":state",
+    "..:cloud_print_interface",
+    "..:native_layer",
+    "../data:destination",
+    "../data:destination_store",
+    "../data:document_info",
+    "../data:invitation_store",
+    "../data:measurement_system",
+    "../data:user_info",
+    "//ui/webui/resources/js:event_tracker",
+    "//ui/webui/resources/js:util",
+    "//ui/webui/resources/js:webui_listener_tracker",
+  ]
+}
+
+js_library("header") {
+  deps = [
+    ":model",
+    ":settings_behavior",
+    ":state",
+    "../data:destination",
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js:load_time_data",
+  ]
+}
+
+js_library("destination_settings") {
+  deps = [
+    ":destination_dialog",
+    ":settings_section_behavior",
+    ":state",
+    "../data:destination",
+    "../data:destination_store",
+    "../data:invitation_store",
+    "../data:user_info",
+    "//ui/webui/resources/cr_elements/cr_lazy_render:cr_lazy_render",
+    "//ui/webui/resources/js:i18n_behavior",
+  ]
+}
+
+js_library("pages_settings") {
+  deps = [
+    ":input_behavior",
+    ":settings_behavior",
+    ":settings_section_behavior",
+    "../data:document_info",
+    "//ui/webui/resources/js:load_time_data",
+  ]
+}
+
+js_library("copies_settings") {
+  deps = [
+    ":number_settings_section",
+    ":settings_behavior",
+    ":settings_section_behavior",
+  ]
+}
+
+js_library("layout_settings") {
+  deps = [
+    ":settings_behavior",
+    ":settings_section_behavior",
+  ]
+}
+
+js_library("color_settings") {
+  deps = [
+    ":settings_behavior",
+    ":settings_section_behavior",
+  ]
+}
+
+js_library("media_size_settings") {
+  deps = [
+    ":settings_behavior",
+    ":settings_section_behavior",
+    ":settings_select",
+  ]
+}
+
+js_library("margins_settings") {
+  deps = [
+    ":settings_behavior",
+    ":settings_section_behavior",
+  ]
+}
+
+js_library("dpi_settings") {
+  deps = [
+    ":settings_behavior",
+    ":settings_section_behavior",
+    ":settings_select",
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js:load_time_data",
+  ]
+}
+
+js_library("scaling_settings") {
+  deps = [
+    ":number_settings_section",
+    ":settings_behavior",
+    ":settings_section_behavior",
+    "../data:document_info",
+  ]
+}
+
+js_library("other_options_settings") {
+  deps = [
+    ":settings_behavior",
+    ":settings_section_behavior",
+  ]
+}
+
+js_library("advanced_options_settings") {
+  deps = [
+    ":advanced_settings_dialog",
+    ":settings_behavior",
+    ":settings_section_behavior",
+    "../data:destination",
+  ]
+}
+
+js_library("more_settings") {
+  deps = [
+    ":settings_section_behavior",
+    "//ui/webui/resources/js:i18n_behavior",
+  ]
+}
+
+js_library("number_settings_section") {
+  deps = [
+    ":input_behavior",
+  ]
+}
+
+js_library("settings_select") {
+  deps = [
+    ":settings_behavior",
+    "..:print_preview_utils",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("settings_behavior") {
+  deps = [
+    "//ui/webui/resources/js:assert",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("settings_section_behavior") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("input_behavior") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("link_container") {
+  deps = [
+    "../data:destination",
+    "//ui/webui/resources/js:assert",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("preview_area") {
+  deps = [
+    ":margin_control_container",
+    ":model",
+    ":settings_behavior",
+    ":state",
+    "..:native_layer",
+    "..:print_preview_utils",
+    "../../pdf:pdf_scripting_api",
+    "../data:coordinate2d",
+    "../data:destination",
+    "../data:document_info",
+    "../data:margins",
+    "../data:printable_area",
+    "../data:size",
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js:i18n_behavior",
+    "//ui/webui/resources/js:util",
+    "//ui/webui/resources/js:web_ui_listener_behavior",
+  ]
+}
+
+js_library("margin_control_container") {
+  deps = [
+    ":margin_control",
+    ":settings_behavior",
+    "../data:coordinate2d",
+    "../data:margins",
+    "../data:measurement_system",
+    "../data:size",
+    "//ui/webui/resources/js:event_tracker",
+  ]
+  externs_list = [ "$externs_path/pending.js" ]
+}
+
+js_library("margin_control") {
+  deps = [
+    ":input_behavior",
+    "../data:coordinate2d",
+    "../data:margins",
+    "../data:size",
+  ]
+}
+
+js_library("destination_dialog") {
+  deps = [
+    ":destination_list",
+    ":print_preview_search_box",
+    ":provisional_destination_resolver",
+    "..:metrics",
+    "../data:destination",
+    "../data:destination_store",
+    "../data:invitation",
+    "../data:invitation_store",
+    "../data:user_info",
+    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
+    "//ui/webui/resources/js:event_tracker",
+    "//ui/webui/resources/js:i18n_behavior",
+  ]
+}
+
+js_library("destination_list") {
+  deps = [
+    ":destination_list_item",
+    "..:native_layer",
+    "../data:destination",
+    "//ui/webui/resources/js:i18n_behavior",
+  ]
+}
+
+js_library("destination_list_item") {
+  deps = [
+    ":highlight_utils",
+    "..:native_layer",
+    "../data:destination",
+    "//ui/webui/resources/js:load_time_data",
+  ]
+}
+
+js_library("advanced_settings_dialog") {
+  deps = [
+    ":advanced_settings_item",
+    ":print_preview_search_box",
+    ":settings_behavior",
+    "..:metrics",
+    "../data:destination",
+    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
+    "//ui/webui/resources/js:i18n_behavior",
+  ]
+}
+
+js_library("advanced_settings_item") {
+  deps = [
+    ":highlight_utils",
+    ":settings_behavior",
+    "..:print_preview_utils",
+    "../data:destination",
+  ]
+}
+
+js_library("print_preview_search_box") {
+  deps = [
+    "//ui/webui/resources/cr_elements/cr_search_field:cr_search_field_behavior",
+  ]
+}
+
+js_library("provisional_destination_resolver") {
+  deps = [
+    "../data:destination",
+    "../data:destination_store",
+    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js:i18n_behavior",
+  ]
+}
+
+js_library("highlight_utils") {
+  deps = [
+    "//ui/webui/resources/js:search_highlight_utils",
+  ]
+}
+
+js_library("model") {
+  deps = [
+    ":settings_behavior",
+    "../data:destination",
+    "../data:document_info",
+    "../data:margins",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("state") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+  ]
+}
diff --git a/chrome/browser/resources/print_preview/new/compiled_resources2.gyp b/chrome/browser/resources/print_preview/new/compiled_resources2.gyp
deleted file mode 100644
index dd5aeaa9..0000000
--- a/chrome/browser/resources/print_preview/new/compiled_resources2.gyp
+++ /dev/null
@@ -1,366 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-{
-  'targets': [
-    {
-      'target_name': 'app',
-      'dependencies': [
-        'header',
-        'destination_settings',
-        'pages_settings',
-        'copies_settings',
-        'layout_settings',
-        'color_settings',
-        'media_size_settings',
-        'margins_settings',
-        'dpi_settings',
-        'scaling_settings',
-        'other_options_settings',
-        'advanced_options_settings',
-        'more_settings',
-        'link_container',
-        'preview_area',
-        'model',
-        'state',
-        '../compiled_resources2.gyp:cloud_print_interface',
-        '../compiled_resources2.gyp:native_layer',
-        '../data/compiled_resources2.gyp:destination',
-        '../data/compiled_resources2.gyp:destination_store',
-        '../data/compiled_resources2.gyp:invitation_store',
-        '../data/compiled_resources2.gyp:document_info',
-        '../data/compiled_resources2.gyp:measurement_system',
-        '../data/compiled_resources2.gyp:user_info',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:event_tracker',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:webui_listener_tracker',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'header',
-      'dependencies': [
-        '../data/compiled_resources2.gyp:destination',
-        'model',
-        'settings_behavior',
-        'state',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'destination_settings',
-      'dependencies': [
-        '../data/compiled_resources2.gyp:destination',
-        '../data/compiled_resources2.gyp:destination_store',
-        '../data/compiled_resources2.gyp:invitation_store',
-        '../data/compiled_resources2.gyp:user_info',
-        'destination_dialog',
-        'settings_section_behavior',
-        'state',
-        '<(DEPTH)/ui/webui/resources/cr_elements/cr_lazy_render/compiled_resources2.gyp:cr_lazy_render',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'pages_settings',
-      'dependencies': [
-        'input_behavior',
-        'settings_behavior',
-        'settings_section_behavior',
-        '../data/compiled_resources2.gyp:document_info',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'copies_settings',
-      'dependencies': [
-        'number_settings_section',
-        'settings_behavior',
-        'settings_section_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'layout_settings',
-      'dependencies': [
-        'settings_behavior',
-        'settings_section_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'color_settings',
-      'dependencies': [
-        'settings_behavior',
-        'settings_section_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'media_size_settings',
-      'dependencies': [
-        'settings_behavior',
-        'settings_section_behavior',
-        'settings_select',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'margins_settings',
-      'dependencies': [
-        'settings_behavior',
-        'settings_section_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'dpi_settings',
-      'dependencies': [
-        'settings_behavior',
-        'settings_section_behavior',
-        'settings_select',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'scaling_settings',
-      'dependencies': [
-        '../data/compiled_resources2.gyp:document_info',
-        'number_settings_section',
-        'settings_behavior',
-        'settings_section_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'other_options_settings',
-      'dependencies': [
-        'settings_behavior',
-        'settings_section_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'advanced_options_settings',
-      'dependencies': [
-        '../data/compiled_resources2.gyp:destination',
-        'advanced_settings_dialog',
-        'settings_behavior',
-        'settings_section_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'more_settings',
-      'dependencies': [
-        'settings_section_behavior',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'number_settings_section',
-      'dependencies': [
-        'input_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'settings_select',
-      'dependencies': [
-        'settings_behavior',
-        '../compiled_resources2.gyp:print_preview_utils',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'settings_behavior',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'settings_section_behavior',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'input_behavior',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'link_container',
-      'dependencies': [
-        '../data/compiled_resources2.gyp:destination',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'preview_area',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
-        '../../pdf/compiled_resources2.gyp:pdf_scripting_api',
-        '../compiled_resources2.gyp:native_layer',
-        '../compiled_resources2.gyp:print_preview_utils',
-        '../data/compiled_resources2.gyp:destination',
-        '../data/compiled_resources2.gyp:document_info',
-        '../data/compiled_resources2.gyp:coordinate2d',
-        '../data/compiled_resources2.gyp:size',
-        '../data/compiled_resources2.gyp:margins',
-        '../data/compiled_resources2.gyp:printable_area',
-        'margin_control_container',
-        'model',
-        'settings_behavior',
-        'state',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'margin_control_container',
-      'dependencies': [
-        '../data/compiled_resources2.gyp:coordinate2d',
-        '../data/compiled_resources2.gyp:margins',
-        '../data/compiled_resources2.gyp:measurement_system',
-        '../data/compiled_resources2.gyp:size',
-        'margin_control',
-        'settings_behavior',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:event_tracker',
-        '<(EXTERNS_GYP):pending',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'margin_control',
-      'dependencies': [
-        '../data/compiled_resources2.gyp:coordinate2d',
-        '../data/compiled_resources2.gyp:margins',
-        '../data/compiled_resources2.gyp:size',
-        'input_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'destination_dialog',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/cr_elements/cr_dialog/compiled_resources2.gyp:cr_dialog',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:event_tracker',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
-        '../compiled_resources2.gyp:metrics',
-        '../data/compiled_resources2.gyp:destination',
-        '../data/compiled_resources2.gyp:destination_store',
-        '../data/compiled_resources2.gyp:invitation',
-        '../data/compiled_resources2.gyp:invitation_store',
-        '../data/compiled_resources2.gyp:user_info',
-        'destination_list',
-        'print_preview_search_box',
-        'provisional_destination_resolver',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'destination_list',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
-        '../compiled_resources2.gyp:native_layer',
-        '../data/compiled_resources2.gyp:destination',
-        'destination_list_item',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'destination_list_item',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
-        'highlight_utils',
-        '../compiled_resources2.gyp:native_layer',
-        '../data/compiled_resources2.gyp:destination',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'advanced_settings_dialog',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/cr_elements/cr_dialog/compiled_resources2.gyp:cr_dialog',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
-        '../compiled_resources2.gyp:metrics',
-        '../data/compiled_resources2.gyp:destination',
-        'advanced_settings_item',
-        'print_preview_search_box',
-        'settings_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'advanced_settings_item',
-      'dependencies': [
-        'highlight_utils',
-        '../compiled_resources2.gyp:print_preview_utils',
-        '../data/compiled_resources2.gyp:destination',
-        'settings_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'print_preview_search_box',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/cr_elements/cr_search_field/compiled_resources2.gyp:cr_search_field_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'provisional_destination_resolver',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/cr_elements/cr_dialog/compiled_resources2.gyp:cr_dialog',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
-        '../data/compiled_resources2.gyp:destination',
-        '../data/compiled_resources2.gyp:destination_store',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'highlight_utils',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:search_highlight_utils',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'model',
-      'dependencies': [
-        'settings_behavior',
-        '../data/compiled_resources2.gyp:destination',
-        '../data/compiled_resources2.gyp:document_info',
-        '../data/compiled_resources2.gyp:margins',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'state',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    }
-  ],
-}
diff --git a/chrome/browser/resources/print_preview/print_preview.js b/chrome/browser/resources/print_preview/print_preview.js
index 15f928aa..3702bf1 100644
--- a/chrome/browser/resources/print_preview/print_preview.js
+++ b/chrome/browser/resources/print_preview/print_preview.js
@@ -1222,7 +1222,7 @@
         this.nativeLayer_.uiLoadedForTest();
       } else {
         combobox.value = 'landscape';
-        this.layoutSettings_.onSelectChange_();
+        this.layoutSettings_.onSelectChange();
       }
     },
 
@@ -1286,7 +1286,7 @@
         this.nativeLayer_.uiLoadedForTest();
       } else if (margins >= 0 && margins < combobox.length) {
         combobox.selectedIndex = margins;
-        this.marginSettings_.onSelectChange_();
+        this.marginSettings_.onSelectChange();
       } else {
         this.nativeLayer_.uiFailedLoadingForTest();
       }
diff --git a/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.js b/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.js
index 9c54b54..960f277 100644
--- a/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.js
+++ b/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.js
@@ -48,7 +48,7 @@
      */
     this.searchBubble_ = null;
 
-    /** @private {!EventTracker} */
+    /** @protected {!EventTracker} */
     this.tracker_ = new EventTracker();
   }
 
diff --git a/chrome/browser/resources/print_preview/settings/layout_settings.js b/chrome/browser/resources/print_preview/settings/layout_settings.js
index ec423d2..93246fc 100644
--- a/chrome/browser/resources/print_preview/settings/layout_settings.js
+++ b/chrome/browser/resources/print_preview/settings/layout_settings.js
@@ -45,7 +45,7 @@
     /** @override */
     enterDocument: function() {
       print_preview.SettingsSection.prototype.enterDocument.call(this);
-      this.tracker.add(this.select_, 'change', this.onSelectChange_.bind(this));
+      this.tracker.add(this.select_, 'change', this.onSelectChange.bind(this));
       this.tracker.add(
           this.landscapeTicketItem_,
           print_preview.ticket_items.TicketItem.EventType.CHANGE,
@@ -55,9 +55,8 @@
     /**
      * Called when the select element is changed. Updates the print ticket
      * layout selection.
-     * @private
      */
-    onSelectChange_: function() {
+    onSelectChange: function() {
       const select = this.select_;
       const isLandscape =
           select.options[select.selectedIndex].value == 'landscape';
diff --git a/chrome/browser/resources/print_preview/settings/margin_settings.js b/chrome/browser/resources/print_preview/settings/margin_settings.js
index 4e8168d..6af43ad 100644
--- a/chrome/browser/resources/print_preview/settings/margin_settings.js
+++ b/chrome/browser/resources/print_preview/settings/margin_settings.js
@@ -53,7 +53,7 @@
     enterDocument: function() {
       print_preview.SettingsSection.prototype.enterDocument.call(this);
       this.tracker.add(
-          assert(this.select_), 'change', this.onSelectChange_.bind(this));
+          assert(this.select_), 'change', this.onSelectChange.bind(this));
       this.tracker.add(
           this.marginsTypeTicketItem_,
           print_preview.ticket_items.TicketItem.EventType.CHANGE,
@@ -62,7 +62,6 @@
 
     /**
      * @return {HTMLSelectElement} Select element containing the margin options.
-     * @private
      */
     get select_() {
       return this.getElement().getElementsByClassName(
@@ -72,9 +71,8 @@
     /**
      * Called when the select element is changed. Updates the print ticket
      * margin type.
-     * @private
      */
-    onSelectChange_: function() {
+    onSelectChange: function() {
       const select = this.select_;
       const marginsType =
           /** @type {!print_preview.ticket_items.MarginsTypeValue} */ (
diff --git a/chrome/browser/resources/print_preview/settings/other_options_settings.js b/chrome/browser/resources/print_preview/settings/other_options_settings.js
index ec3d88b..1890165 100644
--- a/chrome/browser/resources/print_preview/settings/other_options_settings.js
+++ b/chrome/browser/resources/print_preview/settings/other_options_settings.js
@@ -218,7 +218,10 @@
       $('rasterize-container').hidden = !this.rasterizeEnabled_;
     },
 
-    /** @override */
+    /**
+     * @public
+     * @override
+     */
     updateUiStateInternal: function() {
       if (this.isAvailable()) {
         for (let i = 0; i < this.elements_.length; i++)
diff --git a/chrome/browser/resources/print_preview/settings/scaling_settings.js b/chrome/browser/resources/print_preview/settings/scaling_settings.js
index a417404..5a8e111 100644
--- a/chrome/browser/resources/print_preview/settings/scaling_settings.js
+++ b/chrome/browser/resources/print_preview/settings/scaling_settings.js
@@ -176,7 +176,7 @@
     /** @override */
     isSectionVisibleInternal: function() {
       return this.fitToPageTicketItem_.isCapabilityAvailable() ||
-          (!this.collapseContent_ &&
+          (!this.collapseContent &&
            this.scalingTicketItem_.isCapabilityAvailable());
     },
 
diff --git a/chrome/browser/resources/print_preview/settings/settings_section_select.js b/chrome/browser/resources/print_preview/settings/settings_section_select.js
index fb20c2d..f752d96 100644
--- a/chrome/browser/resources/print_preview/settings/settings_section_select.js
+++ b/chrome/browser/resources/print_preview/settings/settings_section_select.js
@@ -76,14 +76,14 @@
       }
       // Should the select content be updated?
       const sameContent =
-          this.ticketItem_.capability.option.length == select.length &&
-          this.ticketItem_.capability.option.every(function(option, index) {
+          this.ticketItem_.capability().option.length == select.length &&
+          this.ticketItem_.capability().option.every(function(option, index) {
             return select.options[index].value == JSON.stringify(option);
           });
       let indexToSelect = select.selectedIndex;
       if (!sameContent) {
         select.innerHTML = '';
-        this.ticketItem_.capability.option.forEach(function(option, index) {
+        this.ticketItem_.capability().option.forEach(function(option, index) {
           const selectOption = document.createElement('option');
           selectOption.text = this.getCustomDisplayName_(option) ||
               this.getDefaultDisplayName_(option);
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index e423e26..d35d677 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -103,6 +103,7 @@
 js_type_check("settings_resources") {
   deps = [
     ":extension_control_browser_proxy",
+    ":find_shortcut_behavior",
     ":focus_row_behavior",
     ":global_scroll_target_behavior",
     ":lifetime_browser_proxy",
@@ -121,6 +122,14 @@
   externs_list = [ "$externs_path/chrome_send.js" ]
 }
 
+js_library("find_shortcut_behavior") {
+  deps = [
+    "//third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior:iron-a11y-keys-behavior-extracted",
+    "//ui/webui/resources/js:assert",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
 js_library("focus_row_behavior") {
   deps = [
     "//ui/webui/resources/js/cr/ui:focus_row",
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html
index dddd055..d86a5c2f 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.html
+++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -305,7 +305,7 @@
               restamp>
             <settings-section page-title="$i18n{resetPageTitle}"
                 section="reset">
-              <settings-reset-page></settings-reset-page>
+              <settings-reset-page prefs="{{prefs}}"></settings-reset-page>
             </settings-section>
           </template>
         </div>
diff --git a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html b/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html
index db66f93..7e00642 100644
--- a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html
+++ b/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html
@@ -1,6 +1,7 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
 <link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
@@ -63,7 +64,7 @@
       }
 
       .top-aligned-settings-box {
-        align-items: start;
+        align-items: center;
         /* override settings-box min-height since we use vertical padding */
         min-height: 0;
         padding: 15px var(--settings-box-row-padding);
@@ -85,10 +86,13 @@
           <span class="secondary">[[explanation_]]</span>
         </div>
       </div>
+      <cr-policy-pref-indicator
+          pref="[[prefs.software_reporter.enabled]]">
+      </cr-policy-pref-indicator>
       <template is="dom-if" if="[[showActionButton_]]">
         <div class="separator"></div>
         <paper-button id="action-button" class="action-button"
-            on-click="proceed_">
+            disabled$="[[!cleanupEnabled_]]" on-click="proceed_">
           [[actionButtonLabel_]]
         </paper-button>
       </template>
diff --git a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.js b/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.js
index 75228e1..89875c8 100644
--- a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.js
+++ b/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.js
@@ -111,6 +111,9 @@
   behaviors: [I18nBehavior, WebUIListenerBehavior],
 
   properties: {
+    /** Preferences state. */
+    prefs: Object,
+
     /** @private */
     title_: {
       type: String,
@@ -136,6 +139,30 @@
     },
 
     /** @private */
+    uploadAllowed_: {
+      type: Boolean,
+      value: true,
+    },
+
+    /** @private */
+    uploadManaged_: {
+      type: Boolean,
+      computed: 'computeUploadManaged_(cleanupManaged_, cleanupEnabled_)',
+    },
+
+    /** @private */
+    cleanupEnabled_: {
+      type: Boolean,
+      value: true,
+    },
+
+    /** @private */
+    cleanupManaged_: {
+      type: Boolean,
+      value: false,
+    },
+
+    /** @private */
     actionButtonLabel_: {
       type: String,
       value: '',
@@ -272,6 +299,9 @@
     this.addWebUIListener(
         'chrome-cleanup-upload-permission-change',
         this.onUploadPermissionChange_.bind(this));
+    this.addWebUIListener(
+        'chrome-cleanup-enabled-change',
+        this.onCleanupEnabledChange_.bind(this));
     this.browserProxy_.registerChromeCleanerObserver();
   },
 
@@ -315,6 +345,16 @@
   },
 
   /**
+   * Uploads are managed if cleanup is controlled by policy and the policy
+   * disables the feature.  If the option is controlled by policy but enables
+   * the feature, there is no difference at all from not being managed.
+   * @return {boolean}
+   */
+  computeUploadManaged_: function() {
+    return this.cleanupManaged_ && !this.cleanupEnabled_;
+  },
+
+  /**
    * @param {string} explanation
    * @return {boolean}
    * @private
@@ -554,17 +594,34 @@
    * @private
    */
   onUploadPermissionChange_: function(enabled) {
-    this.logsUploadPref_ = {
+    this.uploadAllowed_ = enabled;
+    const pref = {
       key: '',
       type: chrome.settingsPrivate.PrefType.BOOLEAN,
-      value: enabled,
+      value: this.uploadAllowed_,
     };
+    if (this.uploadManaged_) {
+      pref.enforcement = chrome.settingsPrivate.Enforcement.ENFORCED;
+      pref.controlledBy = chrome.settingsPrivate.ControlledBy.USER_POLICY;
+    }
+    this.logsUploadPref_ = pref;
+  },
+
+  /**
+   * @param {boolean} managed Whether this is controlled by policy or not.
+   * @param {boolean} enabled Whether cleanup is enabled.
+   * @private
+   */
+  onCleanupEnabledChange_: function(managed, enabled) {
+    this.cleanupManaged_ = managed;
+    this.cleanupEnabled_ = enabled;
+    this.onUploadPermissionChange_(this.uploadAllowed_);
   },
 
   /** @private */
   changeLogsPermission_: function() {
-    const enabled = this.$.chromeCleanupLogsUploadControl.checked;
-    this.browserProxy_.setLogsUploadPermission(enabled);
+    this.uploadAllowed_ = this.$.chromeCleanupLogsUploadControl.checked;
+    this.browserProxy_.setLogsUploadPermission(this.uploadAllowed_);
   },
 
   /**
diff --git a/chrome/browser/resources/settings/controls/controlled_radio_button.html b/chrome/browser/resources/settings/controls/controlled_radio_button.html
index d6fcdf26..018f8dd 100644
--- a/chrome/browser/resources/settings/controls/controlled_radio_button.html
+++ b/chrome/browser/resources/settings/controls/controlled_radio_button.html
@@ -85,31 +85,31 @@
                    var(--primary-text-color));
       }
 
-      :host(:not([controlled_])) {
+      :host(:not([disabled])) {
         @apply --settings-actionable;
       }
 
-      :host([controlled_]) {
+      :host([disabled]) {
         /* Disable pointer events for this whole element, as outer on-tap gets
          * triggered when clicking/tapping anywhere in :host. */
         pointer-events: none;
       }
 
-      :host([controlled_]) :-webkit-any(.circle, .disc) {
+      :host([disabled]) :-webkit-any(.circle, .disc) {
         opacity: .5;
       }
 
-      :host([controlled_]) .circle {
+      :host([disabled]) .circle {
         border-color: var(--paper-radio-button-unchecked-color,
                           var(--primary-text-color));
       }
 
-      :host([controlled_][checked]) .disc {
+      :host([disabled][checked]) .disc {
         background-color: var(--paper-radio-button-unchecked-color,
                               var(--primary-text-color));
       }
 
-      :host([controlled_]) #labelWrapper {
+      :host([disabled]) #labelWrapper {
         opacity: .65;
       }
 
@@ -132,7 +132,7 @@
       <slot></slot>
     </div>
 
-    <template is="dom-if" if="[[showIndicator_(controlled_, name, pref.*)]]">
+    <template is="dom-if" if="[[showIndicator_(disabled, name, pref.*)]]">
       <cr-policy-pref-indicator pref="[[pref]]" on-click="onIndicatorTap_"
           icon-aria-label="[[label]]">
       </cr-policy-pref-indicator>
diff --git a/chrome/browser/resources/settings/controls/controlled_radio_button.js b/chrome/browser/resources/settings/controls/controlled_radio_button.js
index 53bd050..66af565 100644
--- a/chrome/browser/resources/settings/controls/controlled_radio_button.js
+++ b/chrome/browser/resources/settings/controls/controlled_radio_button.js
@@ -18,6 +18,13 @@
       observer: 'checkedChanged_',
     },
 
+    disabled: {
+      type: Boolean,
+      computed: 'computeDisabled_(pref.*)',
+      reflectToAttribute: true,
+      observer: 'disabledChanged_',
+    },
+
     label: {
       type: String,
       value: '',  // Allows the hidden$= binding to run without being set.
@@ -29,17 +36,12 @@
     },
 
     /** @private */
-    controlled_: {
-      type: Boolean,
-      computed: 'computeControlled_(pref.*)',
-      reflectToAttribute: true,
-    },
-
-    /** @private */
     pressed_: Boolean,
   },
 
   hostAttributes: {
+    'aria-disabled': 'false',
+    'aria-checked': 'false',
     role: 'radio',
     tabindex: 0,
   },
@@ -67,19 +69,30 @@
    * @return {boolean} Whether the button is disabled.
    * @private
    */
-  computeControlled_: function() {
+  computeDisabled_: function() {
     return this.pref.enforcement == chrome.settingsPrivate.Enforcement.ENFORCED;
   },
 
   /**
-   * @param {boolean} controlled
-   * @param {string} name
+   * @param {boolean} current
+   * @param {boolean} previous
+   * @private
+   */
+  disabledChanged_: function(current, previous) {
+    if (previous === undefined && !this.disabled)
+      return;
+
+    this.setAttribute('tabindex', this.disabled ? -1 : 0);
+    this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
+  },
+
+  /**
    * @return {boolean}
    * @private
    */
-  showIndicator_: function(controlled, name) {
-    return controlled &&
-        name == Settings.PrefUtil.prefToString(assert(this.pref));
+  showIndicator_: function() {
+    return this.disabled &&
+        this.name == Settings.PrefUtil.prefToString(assert(this.pref));
   },
 
   /**
@@ -87,7 +100,7 @@
    * @private
    */
   onIndicatorTap_: function(e) {
-    // Disallow <controlled-radio-button on-click="..."> when controlled.
+    // Disallow <controlled-radio-button on-click="..."> when disabled.
     e.preventDefault();
     e.stopPropagation();
   },
@@ -97,6 +110,9 @@
    * @private
    */
   updatePressed_: function(e) {
+    if (this.disabled)
+      return;
+
     this.pressed_ = ['down', 'focus'].includes(e.type);
   },
 });
diff --git a/chrome/browser/resources/settings/find_shortcut_behavior.html b/chrome/browser/resources/settings/find_shortcut_behavior.html
new file mode 100644
index 0000000..4fedd0e
--- /dev/null
+++ b/chrome/browser/resources/settings/find_shortcut_behavior.html
@@ -0,0 +1,4 @@
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
+<script src="find_shortcut_behavior.js"></script>
diff --git a/chrome/browser/resources/settings/find_shortcut_behavior.js b/chrome/browser/resources/settings/find_shortcut_behavior.js
new file mode 100644
index 0000000..51103e5b
--- /dev/null
+++ b/chrome/browser/resources/settings/find_shortcut_behavior.js
@@ -0,0 +1,51 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Listens for a find keyboard shortcut (i.e. Ctrl/Cmd+f) wherever
+ * this behavior is applied and invokes canHandleFindShortcut(). If
+ * canHandleFindShortcut() returns true, handleFindShortcut() will be called.
+ * Override these methods in your element in order to use this behavior.
+ */
+
+cr.exportPath('settings');
+
+/** @polymerBehavior */
+settings.FindShortcutBehaviorImpl = {
+  keyBindings: {
+    // <if expr="is_macosx">
+    'meta+f': 'onFindShortcut_',
+    // </if>
+    // <if expr="not is_macosx">
+    'ctrl+f': 'onFindShortcut_',
+    // </if>
+  },
+
+  /** @private */
+  onFindShortcut_: function(e) {
+    if (!e.defaultPrevented && this.canHandleFindShortcut()) {
+      this.handleFindShortcut();
+      e.preventDefault();
+    }
+  },
+
+  /**
+   * @return {boolean}
+   * @protected
+   */
+  canHandleFindShortcut: function() {
+    assertNotReached();
+  },
+
+  /** @protected */
+  handleFindShortcut: function() {
+    assertNotReached();
+  },
+};
+
+/** @polymerBehavior */
+settings.FindShortcutBehavior = [
+  Polymer.IronA11yKeysBehavior,
+  settings.FindShortcutBehaviorImpl,
+];
diff --git a/chrome/browser/resources/settings/languages_page/BUILD.gn b/chrome/browser/resources/settings/languages_page/BUILD.gn
index 6784e76..155a0ac9 100644
--- a/chrome/browser/resources/settings/languages_page/BUILD.gn
+++ b/chrome/browser/resources/settings/languages_page/BUILD.gn
@@ -87,6 +87,8 @@
   deps = [
     ":languages",
     ":languages_types",
+    "..:find_shortcut_behavior",
+    "../settings_page:settings_subpage_search",
     "//ui/webui/resources/cr_elements:cr_scrollable_behavior",
   ]
 }
diff --git a/chrome/browser/resources/settings/languages_page/add_languages_dialog.html b/chrome/browser/resources/settings/languages_page/add_languages_dialog.html
index b6e5f6c..6cae08d0 100644
--- a/chrome/browser/resources/settings/languages_page/add_languages_dialog.html
+++ b/chrome/browser/resources/settings/languages_page/add_languages_dialog.html
@@ -42,7 +42,7 @@
     <cr-dialog id="dialog" close-text="$i18n{close}">
       <div slot="title">$i18n{addLanguagesDialogTitle}</div>
       <div slot="body" scrollable>
-        <settings-subpage-search label="$i18n{searchLanguages}"
+        <settings-subpage-search label="$i18n{searchLanguages}" id="search"
             on-search-changed="onSearchChanged_" autofocus>
         </settings-subpage-search>
         <iron-list class="ripple-padding" scroll-target="[[$$('[slot=body]')]]"
diff --git a/chrome/browser/resources/settings/languages_page/add_languages_dialog.js b/chrome/browser/resources/settings/languages_page/add_languages_dialog.js
index 81e3bf5..3a9182f 100644
--- a/chrome/browser/resources/settings/languages_page/add_languages_dialog.js
+++ b/chrome/browser/resources/settings/languages_page/add_languages_dialog.js
@@ -11,6 +11,7 @@
 
   behaviors: [
     CrScrollableBehavior,
+    settings.FindShortcutBehavior,
   ],
 
   properties: {
@@ -49,6 +50,16 @@
     this.$.dialog.showModal();
   },
 
+  // Override settings.FindShortcutBehavior methods.
+  canHandleFindShortcut: function() {
+    return true;
+  },
+
+  handleFindShortcut: function() {
+    this.$.search.getSearchInput().scrollIntoViewIfNeeded();
+    this.$.search.getSearchInput().focus();
+  },
+
   /**
    * @param {!CustomEvent} e
    * @private
diff --git a/chrome/browser/resources/settings/reset_page/reset_page.html b/chrome/browser/resources/settings/reset_page/reset_page.html
index a8081f3..0727c4b 100644
--- a/chrome/browser/resources/settings/reset_page/reset_page.html
+++ b/chrome/browser/resources/settings/reset_page/reset_page.html
@@ -92,7 +92,8 @@
             associated-control="[[$$('#chromeCleanupSubpageTrigger')]]"
             page-title="$i18n{resetCleanupComputerTrigger}"
             learn-more-url="$i18n{chromeCleanupLearnMoreUrl}">
-          <settings-chrome-cleanup-page></settings-chrome-cleanup-page>
+          <settings-chrome-cleanup-page prefs="[[prefs]]">
+          </settings-chrome-cleanup-page>
         </settings-subpage>
       </template>
       <template is="dom-if" if="[[showIncompatibleApplications_]]">
diff --git a/chrome/browser/resources/settings/reset_page/reset_page.js b/chrome/browser/resources/settings/reset_page/reset_page.js
index 8857cbf..538830d8 100644
--- a/chrome/browser/resources/settings/reset_page/reset_page.js
+++ b/chrome/browser/resources/settings/reset_page/reset_page.js
@@ -21,6 +21,9 @@
   behaviors: [settings.RouteObserverBehavior],
 
   properties: {
+    /** Preferences state. */

+    prefs: Object,

+
     // <if expr="chromeos">
     /** @private */
     showPowerwashDialog_: Boolean,
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index ff02025..f5ae833b 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -610,6 +610,13 @@
                  file="icons.html"
                  type="chrome_html"
                  preprocess="true" />
+      <structure name="IDR_SETTINGS_FIND_SHORTCUT_BEHAVIOR_HTML"
+                 file ="find_shortcut_behavior.html"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_FIND_SHORTCUT_BEHAVIOR_JS"
+                 file ="find_shortcut_behavior.js"
+                 type="chrome_html"
+                 preprocess="true" />
       <structure name="IDR_SETTINGS_POWERWASH_DIALOG_HTML"
                  file="reset_page/powerwash_dialog.html"
                  type="chrome_html" />
diff --git a/chrome/browser/resources/settings/settings_ui/BUILD.gn b/chrome/browser/resources/settings/settings_ui/BUILD.gn
index 610d135..177ee20 100644
--- a/chrome/browser/resources/settings/settings_ui/BUILD.gn
+++ b/chrome/browser/resources/settings/settings_ui/BUILD.gn
@@ -12,6 +12,7 @@
 
 js_library("settings_ui") {
   deps = [
+    "..:find_shortcut_behavior",
     "..:global_scroll_target_behavior",
     "..:page_visibility",
     "../prefs:prefs",
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html
index d59bfb9..e149719 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.html
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -5,6 +5,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_toolbar/cr_toolbar.html">
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+<link rel="import" href="../find_shortcut_behavior.html">
 <link rel="import" href="../global_scroll_target_behavior.html">
 <link rel="import" href="../i18n_setup.html">
 <link rel="import" href="../icons.html">
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index d2da46a..6633fcc 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -20,7 +20,11 @@
 Polymer({
   is: 'settings-ui',
 
-  behaviors: [settings.RouteObserverBehavior, CrContainerShadowBehavior],
+  behaviors: [
+    settings.RouteObserverBehavior,
+    CrContainerShadowBehavior,
+    settings.FindShortcutBehavior,
+  ],
 
   properties: {
     /**
@@ -195,6 +199,16 @@
     this.$.main.searchContents(urlSearchQuery);
   },
 
+  // Override settings.FindShortcutBehavior methods.
+  canHandleFindShortcut: function() {
+    return !this.$.drawer.open &&
+        !document.querySelector('* /deep/ cr-dialog[open]');
+  },
+
+  handleFindShortcut: function() {
+    this.$$('cr-toolbar').getSearchField().showAndFocus();
+  },
+
   /**
    * @param {!CustomEvent} e
    * @private
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_impl_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_impl_win.cc
index d3dcfdf..6c6f49a 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_impl_win.cc
+++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_impl_win.cc
@@ -223,8 +223,10 @@
 ChromeCleanerControllerImpl* ChromeCleanerControllerImpl::GetInstance() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  if (!g_controller)
+  if (!g_controller) {
     g_controller = new ChromeCleanerControllerImpl();
+    g_controller->Init();
+  }
 
   return g_controller;
 }
@@ -392,6 +394,7 @@
 
 void ChromeCleanerControllerImpl::RequestUserInitiatedScan() {
   base::AutoLock autolock(lock_);
+  DCHECK(IsAllowedByPolicy());
   DCHECK(pending_invocation_type_ !=
              SwReporterInvocationType::kUserInitiatedWithLogsAllowed &&
          pending_invocation_type_ !=
@@ -438,6 +441,7 @@
 void ChromeCleanerControllerImpl::Scan(
     const SwReporterInvocation& reporter_invocation) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(IsAllowedByPolicy());
   DCHECK(reporter_invocation.BehaviourIsSupported(
       SwReporterInvocation::BEHAVIOUR_TRIGGER_PROMPT));
 
@@ -521,6 +525,10 @@
   InitiateReboot();
 }
 
+bool ChromeCleanerControllerImpl::IsAllowedByPolicy() {
+  return safe_browsing::SwReporterIsAllowedByPolicy();
+}
+
 ChromeCleanerControllerImpl::ChromeCleanerControllerImpl()
     : real_delegate_(std::make_unique<ChromeCleanerControllerDelegate>()),
       delegate_(real_delegate_.get()),
@@ -530,6 +538,12 @@
 
 ChromeCleanerControllerImpl::~ChromeCleanerControllerImpl() = default;
 
+void ChromeCleanerControllerImpl::Init() {
+  // The default value for logs is determined by whether the cleanup feature is
+  // enabled by policy.
+  logs_enabled_ = IsAllowedByPolicy();
+}
+
 void ChromeCleanerControllerImpl::NotifyObserver(Observer* observer) const {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_impl_win.h b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_impl_win.h
index a288915..fc1d7f4 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_impl_win.h
+++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_impl_win.h
@@ -67,6 +67,7 @@
   void ReplyWithUserResponse(Profile* profile,
                              UserResponse user_response) override;
   void Reboot() override;
+  bool IsAllowedByPolicy() override;
 
   static void ResetInstanceForTesting();
   // Passing in a nullptr as |delegate| resets the delegate to a default
@@ -81,6 +82,8 @@
   ChromeCleanerControllerImpl();
   ~ChromeCleanerControllerImpl() override;
 
+  void Init();
+
   void NotifyObserver(Observer* observer) const;
   void SetStateAndNotifyObservers(State state);
   // Used to invalidate weak pointers and reset accumulated data that is no
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h
index 5cad5de7..3158a50 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h
+++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h
@@ -204,6 +204,9 @@
   // if the system calls to initiate a reboot return success.
   virtual void Reboot() = 0;
 
+  // Returns true if the cleaner is allowed to run by enterprise policy.
+  virtual bool IsAllowedByPolicy() = 0;
+
  protected:
   ChromeCleanerController();
   virtual ~ChromeCleanerController();
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_controller_win.h b/chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_controller_win.h
index 9ae6c96d..93f98f3f9 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_controller_win.h
+++ b/chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_controller_win.h
@@ -34,6 +34,7 @@
   MOCK_METHOD1(Scan, void(const safe_browsing::SwReporterInvocation&));
   MOCK_METHOD2(ReplyWithUserResponse, void(Profile*, UserResponse));
   MOCK_METHOD0(Reboot, void());
+  MOCK_METHOD0(IsAllowedByPolicy, bool());
 };
 
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_browsertest_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_browsertest_win.cc
index 2f108df..189859b8 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_browsertest_win.cc
+++ b/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_browsertest_win.cc
@@ -19,19 +19,26 @@
 #include "base/run_loop.h"
 #include "base/synchronization/lock.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/test_reg_util_win.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/version.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/component_updater/sw_reporter_installer_win.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_controller_win.h"
 #include "chrome/browser/safe_browsing/chrome_cleaner/srt_client_info_win.h"
 #include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/test_launcher_utils.h"
 #include "components/component_updater/pref_names.h"
+#include "components/policy/core/browser/browser_policy_connector.h"
+#include "components/policy/core/common/mock_configuration_policy_provider.h"
+#include "components/policy/policy_constants.h"
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
 #include "components/variations/variations_params_manager.h"
@@ -76,6 +83,92 @@
 };
 
 // Parameters for this test:
+//  - bool: whether the policy is managed or not.
+//  - bool: if managed, whether the policy is forced on or not.
+using ReporterRunnerPolicyTestParams = std::tuple<bool, bool>;
+
+class ReporterRunnerPolicyTest
+    : public InProcessBrowserTest,
+      public ::testing::WithParamInterface<ReporterRunnerPolicyTestParams> {
+ public:
+  ReporterRunnerPolicyTest() {
+    std::tie(is_managed_, is_enabled_) = GetParam();
+    component_updater::SetRegisterSwReporterComponentCallbackForTesting(
+        base::BindOnce(&ReporterRunnerPolicyTest::ComponentRegistered,
+                       base::Unretained(this)));
+  }
+
+  bool is_managed() const { return is_managed_; }
+  bool is_enabled() const { return is_enabled_; }
+
+  void WaitForComponentRegistration() { waiter_.Wait(); }
+
+ private:
+  void SetUpCommandLine(base::CommandLine* command_line) override {}
+
+  // Make sure the component will be installed during the test.
+  void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
+    base::CommandLine default_command_line(base::CommandLine::NO_PROGRAM);
+    InProcessBrowserTest::SetUpDefaultCommandLine(&default_command_line);
+    test_launcher_utils::RemoveCommandLineSwitch(
+        default_command_line, switches::kDisableComponentUpdate, command_line);
+  }
+
+  void SetUpInProcessBrowserTestFixture() override {
+    EXPECT_CALL(provider_, IsInitializationComplete(_))
+        .WillRepeatedly(Return(true));
+    policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
+
+    // Setup polices as needed.
+    if (is_managed_) {
+      policy::PolicyMap policies;
+      policies.Set(policy::key::kChromeCleanupEnabled,
+                   policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
+                   policy::POLICY_SOURCE_PLATFORM,
+                   std::make_unique<base::Value>(is_enabled_), nullptr);
+      provider_.UpdateChromePolicy(policies);
+    }
+  }
+
+  void ComponentRegistered() { waiter_.Signal(); }
+
+  void SetUpOnMainThread() override {}
+
+  void TearDownInProcessBrowserTestFixture() override {}
+
+  registry_util::RegistryOverrideManager registry_override_manager_;
+  policy::MockConfigurationPolicyProvider provider_;
+  Waiter waiter_;
+  bool is_managed_;
+  bool is_enabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReporterRunnerPolicyTest);
+};
+
+IN_PROC_BROWSER_TEST_P(ReporterRunnerPolicyTest, CheckComponent) {
+  WaitForComponentRegistration();
+
+  // If the cleaner is disabled by policy, there should be no reporter
+  // component installed.  Otherwise it should be installed.
+  std::vector<std::string> component_ids =
+      g_browser_process->component_updater()->GetComponentIDs();
+  bool sw_component_registered =
+      std::find(component_ids.begin(), component_ids.end(),
+                component_updater::kSwReporterComponentId) !=
+      component_ids.end();
+  ASSERT_EQ(!is_managed() || is_enabled(), sw_component_registered);
+}
+
+// Tests for kUserInitiatedChromeCleanupsFeature enabled (all invocation types
+// are allowed).
+INSTANTIATE_TEST_CASE_P(
+    PolicyControl,
+    ReporterRunnerPolicyTest,
+    ::testing::Values(ReporterRunnerPolicyTestParams(false, false),
+                      ReporterRunnerPolicyTestParams(true, false),
+                      ReporterRunnerPolicyTestParams(true, true)));
+
+// Parameters for this test:
 //  - SwReporterInvocationType invocation_type_: identifies the type of
 //        invocation being tested.
 //  - const char* old_seed_: The old "Seed" Finch parameter saved in prefs.
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.cc
index 323ab2f..b8474821 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.cc
+++ b/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.cc
@@ -594,6 +594,9 @@
     if (!invocations.version().IsValid() || !local_state)
       return;
 
+    // By this point the reporter should be allowed to run.
+    DCHECK(SwReporterIsAllowedByPolicy());
+
     ReporterRunTimeInfo time_info(local_state);
 
     // The UI should block a new user-initiated run if the reporter is
@@ -1131,6 +1134,16 @@
                                         std::move(invocations));
 }
 
+bool SwReporterIsAllowedByPolicy() {
+  static auto is_allowed = []() {
+    PrefService* local_state = g_browser_process->local_state();
+    return !local_state ||
+           !local_state->IsManagedPreference(prefs::kSwReporterEnabled) ||
+           local_state->GetBoolean(prefs::kSwReporterEnabled);
+  }();
+  return is_allowed;
+}
+
 void SetSwReporterTestingDelegate(SwReporterTestingDelegate* delegate) {
   g_testing_delegate_ = delegate;
 }
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.h b/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.h
index 2d8ed718..e3701eb 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.h
+++ b/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.h
@@ -216,6 +216,9 @@
 void MaybeStartSwReporter(SwReporterInvocationType invocation_type,
                           SwReporterInvocationSequence&& invocations);
 
+// Returns true if the sw_reporter is allowed to run due to enterprise policies.
+bool SwReporterIsAllowedByPolicy();
+
 // A delegate used by tests to implement test doubles (e.g., stubs, fakes, or
 // mocks).
 //
diff --git a/chrome/browser/search/one_google_bar/one_google_bar_fetcher_impl_unittest.cc b/chrome/browser/search/one_google_bar/one_google_bar_fetcher_impl_unittest.cc
index 36753f3..0fe8719c 100644
--- a/chrome/browser/search/one_google_bar/one_google_bar_fetcher_impl_unittest.cc
+++ b/chrome/browser/search/one_google_bar/one_google_bar_fetcher_impl_unittest.cc
@@ -33,11 +33,6 @@
 using testing::SaveArg;
 using testing::StartsWith;
 
-// Needed for GoogleURLTrackerClientStub below.
-namespace net {
-class URLRequestContextGetter;
-}
-
 namespace {
 
 const char kApplicationLocale[] = "de";
@@ -55,7 +50,9 @@
 
   bool IsBackgroundNetworkingEnabled() override { return true; }
   PrefService* GetPrefs() override { return nullptr; }
-  net::URLRequestContextGetter* GetRequestContext() override { return nullptr; }
+  network::SharedURLLoaderFactory* GetURLLoaderFactory() override {
+    return nullptr;
+  }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(GoogleURLTrackerClientStub);
diff --git a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
index 755757f..e90d7074 100644
--- a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
@@ -242,7 +242,8 @@
     VerifyBookmarkModelMatchesFakeServer(kSingleProfileIndex);
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest, InjectedBookmark) {
+IN_PROC_BROWSER_TEST_P(SingleClientBookmarksSyncTestIncludingUssTests,
+                       InjectedBookmark) {
   std::string title = "Montreal Canadiens";
   fake_server::EntityBuilderFactory entity_builder_factory;
   fake_server::BookmarkEntityBuilder bookmark_builder =
@@ -254,7 +255,7 @@
   ASSERT_TRUE(SetupClients());
   ASSERT_TRUE(SetupSync());
 
-  ASSERT_EQ(1, CountBookmarksWithTitlesMatching(kSingleProfileIndex, title));
+  EXPECT_EQ(1, CountBookmarksWithTitlesMatching(kSingleProfileIndex, title));
 }
 
 // Test that a client doesn't mutate the favicon data in the process
@@ -392,21 +393,6 @@
   ASSERT_TRUE(ModelMatchesVerifier(kSingleProfileIndex));
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientBookmarksSyncTestIncludingUssTests,
-                       DownloadBookmark) {
-  std::string title = "Patrick Star";
-  fake_server::EntityBuilderFactory entity_builder_factory;
-  fake_server::BookmarkEntityBuilder bookmark_builder =
-      entity_builder_factory.NewBookmarkEntityBuilder(title);
-  fake_server_->InjectEntity(bookmark_builder.BuildBookmark(
-      GURL("http://en.wikipedia.org/wiki/Patrick_Star")));
-
-  DisableVerifier();
-  ASSERT_TRUE(SetupSync());
-
-  EXPECT_EQ(1, CountBookmarksWithTitlesMatching(kSingleProfileIndex, title));
-}
-
 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest,
                        DownloadDeletedBookmark) {
   std::string title = "Patrick Star";
@@ -477,7 +463,8 @@
   ASSERT_EQ(1, CountBookmarksWithTitlesMatching(kSingleProfileIndex, title));
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest, DownloadBookmarkFolder) {
+IN_PROC_BROWSER_TEST_P(SingleClientBookmarksSyncTestIncludingUssTests,
+                       DownloadBookmarkFolder) {
   const std::string title = "Seattle Sounders FC";
   fake_server::EntityBuilderFactory entity_builder_factory;
   fake_server::BookmarkEntityBuilder bookmark_builder =
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index a3eaf7b5..5f5372a 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1361,6 +1361,9 @@
       "layout_constants.h",
       "location_bar/location_bar.cc",
       "location_bar/location_bar.h",
+      "media_router/cast_dialog_controller.h",
+      "media_router/cast_dialog_model.cc",
+      "media_router/cast_dialog_model.h",
       "media_router/cast_modes_with_media_sources.cc",
       "media_router/cast_modes_with_media_sources.h",
       "media_router/media_cast_mode.cc",
@@ -3157,6 +3160,8 @@
         "views/location_bar/zoom_view.h",
         "views/media_router/cast_dialog_sink_button.cc",
         "views/media_router/cast_dialog_sink_button.h",
+        "views/media_router/cast_dialog_view.cc",
+        "views/media_router/cast_dialog_view.h",
         "views/media_router/media_router_dialog_controller_views.cc",
         "views/media_router/media_router_dialog_controller_views.h",
         "views/media_router/media_router_views_ui.cc",
diff --git a/chrome/browser/ui/app_list/crostini/crostini_installer_view.cc b/chrome/browser/ui/app_list/crostini/crostini_installer_view.cc
index d46043f..645c5856 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_installer_view.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_installer_view.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/metrics/histogram_functions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
@@ -40,6 +41,9 @@
 constexpr int kDownloadSizeInBytes = 300 * 1024 * 1024;
 
 constexpr int kDialogWidth = 448;
+
+constexpr char kCrostiniSetupResultHistogram[] = "Crostini.SetupResult";
+
 }  // namespace
 
 void CrostiniInstallerView::Show(Profile* profile) {
@@ -116,6 +120,9 @@
     // Abort the long-running flow, and prevent our RestartObserver methods
     // being called after "this" has been destroyed.
     crostini::CrostiniManager::GetInstance()->AbortRestartCrostini(restart_id_);
+    RecordSetupResultHistogram(SetupResult::kUserCancelled);
+  } else {
+    RecordSetupResultHistogram(SetupResult::kNotStarted);
   }
   return true;  // Should close the dialog
 }
@@ -174,7 +181,15 @@
   GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize());
 }
 
-void CrostiniInstallerView::HandleError(const base::string16& error_message) {
+void CrostiniInstallerView::HandleError(const base::string16& error_message,
+                                        SetupResult result) {
+  // Only ever set the error once. This check is necessary as the
+  // CrostiniManager can give multiple error callbacks. Only the first should be
+  // shown to the user.
+  if (state_ == State::ERROR)
+    return;
+
+  RecordSetupResultHistogram(result);
   state_ = State::ERROR;
   message_label_->SetVisible(true);
   message_label_->SetText(error_message);
@@ -212,7 +227,8 @@
   if (result != ConciergeClientResult::SUCCESS) {
     LOG(ERROR) << "Failed to install the cros-termina component";
     HandleError(
-        l10n_util::GetStringUTF16(IDS_CROSTINI_INSTALLER_LOAD_TERMINA_ERROR));
+        l10n_util::GetStringUTF16(IDS_CROSTINI_INSTALLER_LOAD_TERMINA_ERROR),
+        SetupResult::kErrorLoadingTermina);
     return;
   }
   VLOG(1) << "cros-termina install success";
@@ -225,8 +241,9 @@
   if (result != ConciergeClientResult::SUCCESS) {
     LOG(ERROR) << "Failed to install start Concierge with error code: "
                << static_cast<int>(result);
-    HandleError(l10n_util::GetStringUTF16(
-        IDS_CROSTINI_INSTALLER_START_CONCIERGE_ERROR));
+    HandleError(
+        l10n_util::GetStringUTF16(IDS_CROSTINI_INSTALLER_START_CONCIERGE_ERROR),
+        SetupResult::kErrorStartingConcierge);
     return;
   }
   VLOG(1) << "Concierge service started";
@@ -240,7 +257,8 @@
     LOG(ERROR) << "Failed to create disk imagewith error code: "
                << static_cast<int>(result);
     HandleError(l10n_util::GetStringUTF16(
-        IDS_CROSTINI_INSTALLER_CREATE_DISK_IMAGE_ERROR));
+                    IDS_CROSTINI_INSTALLER_CREATE_DISK_IMAGE_ERROR),
+                SetupResult::kErrorCreatingDiskImage);
     return;
   }
   VLOG(1) << "Created crostini disk image";
@@ -254,7 +272,8 @@
     LOG(ERROR) << "Failed to start Termina VM with error code: "
                << static_cast<int>(result);
     HandleError(l10n_util::GetStringUTF16(
-        IDS_CROSTINI_INSTALLER_START_TERMINA_VM_ERROR));
+                    IDS_CROSTINI_INSTALLER_START_TERMINA_VM_ERROR),
+                SetupResult::kErrorStartingTermina);
     return;
   }
   VLOG(1) << "Started Termina VM successfully";
@@ -268,8 +287,9 @@
   if (result != ConciergeClientResult::SUCCESS) {
     LOG(ERROR) << "Failed to start container with error code: "
                << static_cast<int>(result);
-    HandleError(l10n_util::GetStringUTF16(
-        IDS_CROSTINI_INSTALLER_START_CONTAINER_ERROR));
+    HandleError(
+        l10n_util::GetStringUTF16(IDS_CROSTINI_INSTALLER_START_CONTAINER_ERROR),
+        SetupResult::kErrorStartingContainer);
     return;
   }
   StepProgress();
@@ -284,5 +304,18 @@
       profile_, kCrostiniDefaultVmName, kCrostiniDefaultContainerName);
 
   StepProgress();
+  RecordSetupResultHistogram(SetupResult::kSuccess);
   GetWidget()->Close();
 }
+
+void CrostiniInstallerView::RecordSetupResultHistogram(SetupResult result) {
+  // Prevent multiple results being logged for a given setup flow. This can
+  // happen due to multiple error callbacks happening in some cases, as well as
+  // the user being able to hit Cancel after any errors occur.
+  if (has_logged_result_)
+    return;
+
+  base::UmaHistogramEnumeration(kCrostiniSetupResultHistogram, result,
+                                SetupResult::kCount);
+  has_logged_result_ = true;
+}
diff --git a/chrome/browser/ui/app_list/crostini/crostini_installer_view.h b/chrome/browser/ui/app_list/crostini/crostini_installer_view.h
index 626a8021..aaf1966 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_installer_view.h
+++ b/chrome/browser/ui/app_list/crostini/crostini_installer_view.h
@@ -28,6 +28,20 @@
     : public views::DialogDelegateView,
       public crostini::CrostiniManager::RestartObserver {
  public:
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
+  enum class SetupResult {
+    kNotStarted = 0,
+    kUserCancelled = 1,
+    kSuccess = 2,
+    kErrorLoadingTermina = 3,
+    kErrorStartingConcierge = 4,
+    kErrorCreatingDiskImage = 5,
+    kErrorStartingTermina = 6,
+    kErrorStartingContainer = 7,
+    kCount = 8
+  };
+
   static void Show(Profile* profile);
 
   // views::DialogDelegateView:
@@ -48,15 +62,6 @@
   static CrostiniInstallerView* GetActiveViewForTesting();
 
  private:
-  explicit CrostiniInstallerView(Profile* profile);
-  ~CrostiniInstallerView() override;
-
-  void HandleError(const base::string16& error_message);
-  void StartContainerFinished(crostini::ConciergeClientResult result);
-  void ShowLoginShell();
-  void StepProgress();
-  void SetMessageLabel();
-
   enum class State {
     PROMPT,  // Prompting the user to allow installation.
     ERROR,   // Something unexpected happened.
@@ -70,6 +75,18 @@
     SHOW_LOGIN_SHELL,      // Showing a new crosh window.
     INSTALL_END = SHOW_LOGIN_SHELL,  // Marker enum for last install state.
   };
+
+  explicit CrostiniInstallerView(Profile* profile);
+  ~CrostiniInstallerView() override;
+
+  void HandleError(const base::string16& error_message, SetupResult result);
+  void StartContainerFinished(crostini::ConciergeClientResult result);
+  void ShowLoginShell();
+  void StepProgress();
+  void SetMessageLabel();
+
+  void RecordSetupResultHistogram(SetupResult result);
+
   State state_ = State::PROMPT;
   views::Label* message_label_ = nullptr;
   views::ProgressBar* progress_bar_ = nullptr;
@@ -78,6 +95,12 @@
   crostini::CrostiniManager::RestartId restart_id_ =
       crostini::CrostiniManager::kUninitializedRestartId;
 
+  // Whether the result has been logged or not is stored to prevent multiple
+  // results being logged for a given setup flow. This can happen due to
+  // multiple error callbacks happening in some cases, as well as the user being
+  // able to hit Cancel after any errors occur.
+  bool has_logged_result_ = false;
+
   base::WeakPtrFactory<CrostiniInstallerView> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(CrostiniInstallerView);
diff --git a/chrome/browser/ui/app_list/crostini/crostini_installer_view_browsertest.cc b/chrome/browser/ui/app_list/crostini/crostini_installer_view_browsertest.cc
index 77826ea..db3433e 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_installer_view_browsertest.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_installer_view_browsertest.cc
@@ -4,13 +4,16 @@
 
 #include "chrome/browser/ui/app_list/crostini/crostini_installer_view.h"
 
+#include "base/metrics/histogram_base.h"
 #include "base/run_loop.h"
+#include "base/test/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chromeos/crostini/crostini_pref_names.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/ui/app_list/app_list_client_impl.h"
 #include "chrome/browser/ui/app_list/app_list_service_impl.h"
 #include "chrome/browser/ui/app_list/crostini/crostini_app_model_builder.h"
+#include "chrome/browser/ui/app_list/crostini/crostini_installer_view.h"
 #include "chrome/browser/ui/app_list/test/chrome_app_list_test_support.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
@@ -82,10 +85,18 @@
 }
 
 IN_PROC_BROWSER_TEST_F(CrostiniInstallerViewBrowserTest, Cancel) {
+  base::HistogramTester histogram_tester;
+
   ShowUi("default");
   EXPECT_NE(nullptr, ActiveView());
   ActiveView()->GetDialogClientView()->CancelWindow();
   EXPECT_TRUE(ActiveView()->GetWidget()->IsClosed());
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(nullptr, ActiveView());
+
+  histogram_tester.ExpectBucketCount(
+      "Crostini.SetupResult",
+      static_cast<base::HistogramBase::Sample>(
+          CrostiniInstallerView::SetupResult::kNotStarted),
+      1);
 }
diff --git a/chrome/browser/ui/external_protocol_dialog_delegate.cc b/chrome/browser/ui/external_protocol_dialog_delegate.cc
index 6c1dfc3c..5fbb500 100644
--- a/chrome/browser/ui/external_protocol_dialog_delegate.cc
+++ b/chrome/browser/ui/external_protocol_dialog_delegate.cc
@@ -63,6 +63,9 @@
   content::WebContents* web_contents = tab_util::GetWebContentsByID(
       render_process_host_id_, render_view_routing_id_);
 
+  if (!web_contents)
+    return;  // The dialog may outlast the WebContents.
+
   if (remember) {
     Profile* profile =
         Profile::FromBrowserContext(web_contents->GetBrowserContext());
diff --git a/chrome/browser/ui/media_router/cast_dialog_controller.h b/chrome/browser/ui/media_router/cast_dialog_controller.h
new file mode 100644
index 0000000..d572005
--- /dev/null
+++ b/chrome/browser/ui/media_router/cast_dialog_controller.h
@@ -0,0 +1,49 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_MEDIA_ROUTER_CAST_DIALOG_CONTROLLER_H_
+#define CHROME_BROWSER_UI_MEDIA_ROUTER_CAST_DIALOG_CONTROLLER_H_
+
+#include "chrome/browser/ui/media_router/media_cast_mode.h"
+#include "chrome/common/media_router/media_route.h"
+#include "chrome/common/media_router/media_sink.h"
+
+namespace media_router {
+
+struct CastDialogModel;
+
+// Controller component of the Cast dialog. Responsible for handling user input,
+// updating the CastDialogModel, and notifying CastDialogView of updates.
+class CastDialogController {
+ public:
+  class Observer {
+   public:
+    virtual ~Observer() = default;
+
+    virtual void OnModelUpdated(const CastDialogModel& model) = 0;
+
+    // Observer should drop its reference to the controller when this is called.
+    virtual void OnControllerInvalidated() = 0;
+  };
+
+  virtual ~CastDialogController() = default;
+
+  // |observer| is notified upon registration, and whenever there is a change to
+  // the dialog model.
+  virtual void AddObserver(Observer* observer) = 0;
+  virtual void RemoveObserver(Observer* observer) = 0;
+
+  // Starts Casting to the given sink. No-op if |sink_id| is invalid or the sink
+  // doesn't support |cast_mode|.
+  virtual void StartCasting(const MediaSink::Id& sink_id,
+                            MediaCastMode cast_mode) = 0;
+
+  // Stops casting by terminating the route given by |route_id|. No-op if the ID
+  // is invalid.
+  virtual void StopCasting(const MediaRoute::Id& route_id) = 0;
+};
+
+}  // namespace media_router
+
+#endif  // CHROME_BROWSER_UI_MEDIA_ROUTER_CAST_DIALOG_CONTROLLER_H_
diff --git a/chrome/browser/ui/media_router/cast_dialog_model.cc b/chrome/browser/ui/media_router/cast_dialog_model.cc
new file mode 100644
index 0000000..2156466
--- /dev/null
+++ b/chrome/browser/ui/media_router/cast_dialog_model.cc
@@ -0,0 +1,15 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/media_router/cast_dialog_model.h"
+
+namespace media_router {
+
+CastDialogModel::CastDialogModel() = default;
+
+CastDialogModel::CastDialogModel(const CastDialogModel& other) = default;
+
+CastDialogModel::~CastDialogModel() = default;
+
+}  // namespace media_router
diff --git a/chrome/browser/ui/media_router/cast_dialog_model.h b/chrome/browser/ui/media_router/cast_dialog_model.h
new file mode 100644
index 0000000..98f7696
--- /dev/null
+++ b/chrome/browser/ui/media_router/cast_dialog_model.h
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_MEDIA_ROUTER_CAST_DIALOG_MODEL_H_
+#define CHROME_BROWSER_UI_MEDIA_ROUTER_CAST_DIALOG_MODEL_H_
+
+#include "base/strings/string16.h"
+#include "chrome/browser/ui/media_router/ui_media_sink.h"
+
+namespace media_router {
+
+// Holds data needed to populate a Cast dialog.
+struct CastDialogModel {
+ public:
+  CastDialogModel();
+  CastDialogModel(const CastDialogModel& other);
+  ~CastDialogModel();
+
+  // The tab ID that the dialog is associated with.
+  // TODO(takumif): Set |tab_id| in the ctor.
+  int tab_id = -1;
+
+  // The header to use at the top of the dialog.
+  // This reflects the current activity associated with the tab.
+  base::string16 dialog_header;
+
+  // Sink data in the order they should be shown in the dialog.
+  std::vector<UIMediaSink> media_sinks;
+};
+
+}  // namespace media_router
+
+#endif  // CHROME_BROWSER_UI_MEDIA_ROUTER_CAST_DIALOG_MODEL_H_
diff --git a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
index f648ebe6..41503bf7 100644
--- a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
+++ b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
@@ -58,10 +58,10 @@
 
   // ExternalProtocolDialogDelegate:
   void DoAccept(const GURL& url, bool remember) const override {
-    // Don't call the base impl because it will actually launch |url|.
     *called_ = true;
     *accept_ = true;
     *remember_ = remember;
+    ExternalProtocolDialogDelegate::DoAccept(url, remember);
   }
 
  private:
@@ -72,9 +72,17 @@
   DISALLOW_COPY_AND_ASSIGN(TestExternalProtocolDialogDelegate);
 };
 
-class ExternalProtocolDialogBrowserTest : public DialogBrowserTest {
+class ExternalProtocolDialogBrowserTest
+    : public DialogBrowserTest,
+      public ExternalProtocolHandler::Delegate {
  public:
-  ExternalProtocolDialogBrowserTest() {}
+  ExternalProtocolDialogBrowserTest() {
+    ExternalProtocolHandler::SetDelegateForTesting(this);
+  }
+
+  ~ExternalProtocolDialogBrowserTest() override {
+    ExternalProtocolHandler::SetDelegateForTesting(nullptr);
+  }
 
   // DialogBrowserTest:
   void ShowUi(const std::string& name) override {
@@ -95,6 +103,30 @@
     test::ExternalProtocolDialogTestApi(dialog_).SetCheckBoxSelected(checked);
   }
 
+  // ExternalProtocolHander::Delegate:
+  scoped_refptr<shell_integration::DefaultProtocolClientWorker>
+  CreateShellWorker(
+      const shell_integration::DefaultWebClientWorkerCallback& callback,
+      const std::string& protocol) override {
+    return nullptr;
+  }
+  ExternalProtocolHandler::BlockState GetBlockState(const std::string& scheme,
+                                                    Profile* profile) override {
+    return ExternalProtocolHandler::DONT_BLOCK;
+  }
+  void BlockRequest() override {}
+  void RunExternalProtocolDialog(const GURL& url,
+                                 int render_process_host_id,
+                                 int routing_id,
+                                 ui::PageTransition page_transition,
+                                 bool has_user_gesture) override {}
+  void LaunchUrlWithoutSecurityCheck(
+      const GURL& url,
+      content::WebContents* web_contents) override {
+    url_did_launch_ = true;
+  }
+  void FinishedProcessingCheck() override {}
+
   base::HistogramTester histogram_tester_;
 
  protected:
@@ -102,6 +134,7 @@
   bool called_ = false;
   bool accept_ = false;
   bool remember_ = false;
+  bool url_did_launch_ = false;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ExternalProtocolDialogBrowserTest);
@@ -113,6 +146,7 @@
   EXPECT_TRUE(called_);
   EXPECT_TRUE(accept_);
   EXPECT_FALSE(remember_);
+  EXPECT_TRUE(url_did_launch_);
   histogram_tester_.ExpectBucketCount(
       ExternalProtocolHandler::kHandleStateMetric,
       ExternalProtocolHandler::LAUNCH, 1);
@@ -126,17 +160,36 @@
   EXPECT_TRUE(called_);
   EXPECT_TRUE(accept_);
   EXPECT_TRUE(remember_);
+  EXPECT_TRUE(url_did_launch_);
   histogram_tester_.ExpectBucketCount(
       ExternalProtocolHandler::kHandleStateMetric,
       ExternalProtocolHandler::CHECKED_LAUNCH, 1);
 }
 
+// Regression test for http://crbug.com/835216. The OS owns the dialog, so it
+// may may outlive the WebContents it is attached to.
+IN_PROC_BROWSER_TEST_F(ExternalProtocolDialogBrowserTest,
+                       TestAcceptAfterCloseTab) {
+  ShowUi(std::string());
+  SetChecked(true);  // |remember_| must be true for the segfault to occur.
+  browser()->tab_strip_model()->CloseAllTabs();
+  EXPECT_TRUE(dialog_->Accept());
+  EXPECT_TRUE(called_);
+  EXPECT_TRUE(accept_);
+  EXPECT_TRUE(remember_);
+  EXPECT_FALSE(url_did_launch_);
+  histogram_tester_.ExpectBucketCount(
+      ExternalProtocolHandler::kHandleStateMetric,
+      ExternalProtocolHandler::DONT_LAUNCH, 1);
+}
+
 IN_PROC_BROWSER_TEST_F(ExternalProtocolDialogBrowserTest, TestCancel) {
   ShowUi(std::string());
   EXPECT_TRUE(dialog_->Cancel());
   EXPECT_FALSE(called_);
   EXPECT_FALSE(accept_);
   EXPECT_FALSE(remember_);
+  EXPECT_FALSE(url_did_launch_);
   histogram_tester_.ExpectBucketCount(
       ExternalProtocolHandler::kHandleStateMetric,
       ExternalProtocolHandler::DONT_LAUNCH, 1);
@@ -150,6 +203,7 @@
   EXPECT_FALSE(called_);
   EXPECT_FALSE(accept_);
   EXPECT_FALSE(remember_);
+  EXPECT_FALSE(url_did_launch_);
   histogram_tester_.ExpectBucketCount(
       ExternalProtocolHandler::kHandleStateMetric,
       ExternalProtocolHandler::DONT_LAUNCH, 1);
@@ -162,6 +216,7 @@
   EXPECT_FALSE(called_);
   EXPECT_FALSE(accept_);
   EXPECT_FALSE(remember_);
+  EXPECT_FALSE(url_did_launch_);
   histogram_tester_.ExpectBucketCount(
       ExternalProtocolHandler::kHandleStateMetric,
       ExternalProtocolHandler::DONT_LAUNCH, 1);
@@ -176,6 +231,7 @@
   EXPECT_FALSE(called_);
   EXPECT_FALSE(accept_);
   EXPECT_FALSE(remember_);
+  EXPECT_FALSE(url_did_launch_);
   histogram_tester_.ExpectBucketCount(
       ExternalProtocolHandler::kHandleStateMetric,
       ExternalProtocolHandler::DONT_LAUNCH, 1);
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_view.cc b/chrome/browser/ui/views/media_router/cast_dialog_view.cc
new file mode 100644
index 0000000..d1225c4
--- /dev/null
+++ b/chrome/browser/ui/views/media_router/cast_dialog_view.cc
@@ -0,0 +1,200 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/media_router/cast_dialog_view.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/media_router/cast_dialog_controller.h"
+#include "chrome/browser/ui/media_router/cast_dialog_model.h"
+#include "chrome/browser/ui/media_router/media_cast_mode.h"
+#include "chrome/browser/ui/media_router/ui_media_sink.h"
+#include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
+#include "chrome/browser/ui/views/media_router/cast_dialog_sink_button.h"
+#include "chrome/common/media_router/media_sink.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/vector_icon_types.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/scroll_view.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/view.h"
+#include "ui/views/window/dialog_client_view.h"
+
+namespace media_router {
+
+// static
+void CastDialogView::ShowDialog(views::View* anchor_view,
+                                CastDialogController* controller) {
+  DCHECK(!instance_);
+  instance_ = new CastDialogView(anchor_view, controller);
+  views::Widget* widget =
+      views::BubbleDialogDelegateView::CreateBubble(instance_);
+  widget->Show();
+}
+
+// static
+void CastDialogView::HideDialog() {
+  if (IsShowing())
+    instance_->GetWidget()->Close();
+  // We also set |instance_| to nullptr in WindowClosing() which is called
+  // asynchronously, because not all paths to close the dialog go through
+  // HideDialog(). We set it here because IsShowing() should be false after
+  // HideDialog() is called.
+  instance_ = nullptr;
+}
+
+// static
+bool CastDialogView::IsShowing() {
+  return instance_ != nullptr;
+}
+
+// static
+views::Widget* CastDialogView::GetCurrentDialogWidget() {
+  return instance_ ? instance_->GetWidget() : nullptr;
+}
+
+bool CastDialogView::ShouldShowCloseButton() const {
+  return true;
+}
+
+base::string16 CastDialogView::GetWindowTitle() const {
+  return dialog_title_;
+}
+
+base::string16 CastDialogView::GetDialogButtonLabel(
+    ui::DialogButton button) const {
+  if (sink_buttons_.empty())
+    return base::string16();
+  return sink_buttons_.at(selected_sink_index_)->GetActionText();
+}
+
+int CastDialogView::GetDialogButtons() const {
+  return ui::DIALOG_BUTTON_OK;
+}
+
+bool CastDialogView::Accept() {
+  scroll_position_ = scroll_view_->GetVisibleRect().y();
+  const UIMediaSink& sink = sink_buttons_.at(selected_sink_index_)->sink();
+  if (sink.allowed_actions & static_cast<int>(UICastAction::CAST_TAB)) {
+    controller_->StartCasting(sink.id, TAB_MIRROR);
+  } else if (sink.allowed_actions & static_cast<int>(UICastAction::STOP)) {
+    controller_->StopCasting(sink.route_id);
+  }
+  return false;
+}
+
+bool CastDialogView::Close() {
+  return Cancel();
+}
+
+void CastDialogView::OnModelUpdated(const CastDialogModel& model) {
+  PopulateScrollView(model);
+  RestoreSinkListState();
+}
+
+void CastDialogView::OnControllerInvalidated() {
+  controller_ = nullptr;
+  // The widget may be null if this is called while the dialog is opening.
+  if (GetWidget())
+    GetWidget()->Close();
+}
+
+CastDialogView::CastDialogView(views::View* anchor_view,
+                               CastDialogController* controller)
+    : BubbleDialogDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT),
+      controller_(controller) {}
+
+CastDialogView::~CastDialogView() {
+  if (controller_)
+    controller_->RemoveObserver(this);
+}
+
+void CastDialogView::ButtonPressed(views::Button* sender,
+                                   const ui::Event& event) {
+  SelectSinkAtIndex(sender->tag());
+}
+
+void CastDialogView::Init() {
+  auto* provider = ChromeLayoutProvider::Get();
+  set_margins(
+      gfx::Insets(provider->GetDistanceMetric(
+                      views::DISTANCE_DIALOG_CONTENT_MARGIN_TOP_CONTROL),
+                  0,
+                  provider->GetDistanceMetric(
+                      views::DISTANCE_DIALOG_CONTENT_MARGIN_BOTTOM_CONTROL),
+                  0));
+  SetLayoutManager(std::make_unique<views::FillLayout>());
+  controller_->AddObserver(this);
+}
+
+void CastDialogView::WindowClosing() {
+  if (instance_ == this)
+    instance_ = nullptr;
+}
+
+void CastDialogView::RestoreSinkListState() {
+  if (selected_sink_index_ < sink_buttons_.size()) {
+    sink_buttons_.at(selected_sink_index_)->SnapInkDropToActivated();
+    SelectSinkAtIndex(selected_sink_index_);
+  } else if (sink_buttons_.size() > 0u) {
+    sink_buttons_.at(0)->SnapInkDropToActivated();
+    SelectSinkAtIndex(0);
+  }
+
+  views::ScrollBar* scroll_bar =
+      const_cast<views::ScrollBar*>(scroll_view_->vertical_scroll_bar());
+  if (scroll_bar)
+    scroll_view_->ScrollToPosition(scroll_bar, scroll_position_);
+}
+
+void CastDialogView::PopulateScrollView(const CastDialogModel& model) {
+  dialog_title_ = model.dialog_header;
+  if (!scroll_view_) {
+    scroll_view_ = new views::ScrollView();
+    AddChildView(scroll_view_);
+    constexpr int kSinkButtonHeight = 50;
+    scroll_view_->ClipHeightTo(0, kSinkButtonHeight * 10);
+  }
+  scroll_view_->SetContents(CreateSinkListView(model.media_sinks));
+
+  // The widget may be null if this is called while the dialog is opening.
+  if (GetWidget())
+    SizeToContents();
+  Layout();
+}
+
+views::View* CastDialogView::CreateSinkListView(
+    const std::vector<UIMediaSink>& sinks) {
+  sink_buttons_.clear();
+  views::View* view = new views::View();
+  view->SetLayoutManager(
+      std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
+  for (size_t i = 0; i < sinks.size(); i++) {
+    const UIMediaSink& sink = sinks.at(i);
+    CastDialogSinkButton* sink_button = new CastDialogSinkButton(this, sink);
+    sink_button->set_tag(i);
+    sink_buttons_.push_back(sink_button);
+    view->AddChildView(sink_button);
+  }
+  return view;
+}
+
+void CastDialogView::SelectSinkAtIndex(size_t index) {
+  if (selected_sink_index_ != index &&
+      selected_sink_index_ < sink_buttons_.size()) {
+    sink_buttons_.at(selected_sink_index_)->SetSelected(false);
+  }
+  CastDialogSinkButton* selected_button = sink_buttons_.at(index);
+  selected_button->SetSelected(true);
+  selected_sink_index_ = index;
+
+  // Update the text on the main action button.
+  DialogModelChanged();
+}
+
+// static
+CastDialogView* CastDialogView::instance_ = nullptr;
+
+}  // namespace media_router
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_view.h b/chrome/browser/ui/views/media_router/cast_dialog_view.h
new file mode 100644
index 0000000..a34521b
--- /dev/null
+++ b/chrome/browser/ui/views/media_router/cast_dialog_view.h
@@ -0,0 +1,109 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_VIEW_H_
+
+#include "chrome/browser/ui/media_router/cast_dialog_controller.h"
+#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/controls/button/button.h"
+
+namespace media_router {
+
+class CastDialogSinkButton;
+struct UIMediaSink;
+
+// View component of the Cast dialog that allows users to start and stop Casting
+// to devices. The list of devices used to populate the dialog is supplied by
+// CastDialogModel.
+class CastDialogView : public views::BubbleDialogDelegateView,
+                       public views::ButtonListener,
+                       public CastDialogController::Observer {
+ public:
+  // Instantiates and shows the singleton dialog. The dialog must not be
+  // currently shown.
+  static void ShowDialog(views::View* anchor_view,
+                         CastDialogController* controller);
+
+  // No-op if the dialog is currently not shown.
+  static void HideDialog();
+
+  static bool IsShowing();
+
+  // Returns nullptr if the dialog is currently not shown.
+  static views::Widget* GetCurrentDialogWidget();
+
+  // views::WidgetDelegateView:
+  bool ShouldShowCloseButton() const override;
+
+  // views::WidgetDelegate:
+  base::string16 GetWindowTitle() const override;
+
+  // ui::DialogModel:
+  base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
+  int GetDialogButtons() const override;
+
+  // views::DialogDelegate:
+  bool Accept() override;
+  bool Close() override;
+
+  // CastDialogController::Observer:
+  void OnModelUpdated(const CastDialogModel& model) override;
+  void OnControllerInvalidated() override;
+
+  // views::ButtonListener:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
+  // Called by tests.
+  const std::vector<CastDialogSinkButton*>& sink_buttons_for_test() const {
+    return sink_buttons_;
+  }
+
+ private:
+  CastDialogView(views::View* anchor_view, CastDialogController* controller);
+  ~CastDialogView() override;
+
+  // views::BubbleDialogDelegateView:
+  void Init() override;
+  void WindowClosing() override;
+
+  // Apply the stored sink selection and scroll state.
+  void RestoreSinkListState();
+
+  // Populate the scroll view containing sinks using the data in |model|.
+  void PopulateScrollView(const CastDialogModel& model);
+
+  views::View* CreateSinkListView(const std::vector<UIMediaSink>& sinks);
+
+  void SelectSinkAtIndex(size_t index);
+
+  // The singleton dialog instance. This is a nullptr when a dialog is not
+  // shown.
+  static CastDialogView* instance_;
+
+  // Title shown at the top of the dialog.
+  base::string16 dialog_title_;
+
+  // The index of the selected item on the sink list.
+  size_t selected_sink_index_ = 0;
+
+  // Contains references to sink buttons in the order they appear.
+  std::vector<CastDialogSinkButton*> sink_buttons_;
+
+  CastDialogController* controller_;
+
+  // ScrollView containing the list of sink buttons.
+  views::ScrollView* scroll_view_ = nullptr;
+
+  // How much |scroll_view_| is scrolled downwards in pixels. Whenever the sink
+  // list is updated the scroll position gets reset, so we must manually restore
+  // it to this value.
+  int scroll_position_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(CastDialogView);
+};
+
+}  // namespace media_router
+
+#endif  // CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_VIEW_H_
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_view_unittest.cc b/chrome/browser/ui/views/media_router/cast_dialog_view_unittest.cc
new file mode 100644
index 0000000..29be70e
--- /dev/null
+++ b/chrome/browser/ui/views/media_router/cast_dialog_view_unittest.cc
@@ -0,0 +1,166 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/media_router/cast_dialog_view.h"
+
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/media_router/cast_dialog_controller.h"
+#include "chrome/browser/ui/media_router/cast_dialog_model.h"
+#include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
+#include "chrome/browser/ui/views/media_router/cast_dialog_sink_button.h"
+#include "chrome/grit/generated_resources.h"
+#include "chrome/test/views/chrome_views_test_base.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/views/widget/widget.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::WithArg;
+
+namespace media_router {
+
+namespace {
+
+UIMediaSink CreateAvailableSink() {
+  UIMediaSink sink;
+  sink.id = "sink_available";
+  sink.state = UIMediaSinkState::AVAILABLE;
+  sink.allowed_actions = static_cast<int>(UICastAction::CAST_TAB);
+  return sink;
+}
+
+UIMediaSink CreateConnectedSink() {
+  UIMediaSink sink;
+  sink.id = "sink_connected";
+  sink.state = UIMediaSinkState::CONNECTED;
+  sink.allowed_actions = static_cast<int>(UICastAction::STOP);
+  return sink;
+}
+
+CastDialogModel CreateModelWithSinks(std::vector<UIMediaSink> sinks) {
+  CastDialogModel model;
+  model.dialog_header = base::UTF8ToUTF16("Dialog header");
+  model.media_sinks = std::move(sinks);
+  return model;
+}
+
+}  // namespace
+
+class MockCastDialogController : public CastDialogController {
+ public:
+  MOCK_METHOD1(AddObserver, void(CastDialogController::Observer* observer));
+  MOCK_METHOD1(RemoveObserver, void(CastDialogController::Observer* observer));
+  MOCK_METHOD2(StartCasting,
+               void(const std::string& sink_id, MediaCastMode cast_mode));
+  MOCK_METHOD1(StopCasting, void(const std::string& route_id));
+};
+
+class CastDialogViewTest : public ChromeViewsTestBase {
+ protected:
+  void SetUp() override {
+    ChromeViewsTestBase::SetUp();
+
+    // Create an anchor for the dialog.
+    views::Widget::InitParams params =
+        CreateParams(views::Widget::InitParams::TYPE_WINDOW);
+    params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+    anchor_widget_ = std::make_unique<views::Widget>();
+    anchor_widget_->Init(params);
+    anchor_widget_->Show();
+  }
+
+  void TearDown() override {
+    anchor_widget_.reset();
+    ChromeViewsTestBase::TearDown();
+  }
+
+  void InitializeDialogWithModel(const CastDialogModel& model) {
+    EXPECT_CALL(controller_, AddObserver(_))
+        .WillOnce(
+            WithArg<0>(Invoke([this](CastDialogController::Observer* observer) {
+              dialog_ = static_cast<CastDialogView*>(observer);
+            })));
+    CastDialogView::ShowDialog(anchor_widget_->GetContentsView(), &controller_);
+
+    dialog_->OnModelUpdated(model);
+  }
+
+  void SelectSinkAtIndex(int index) {
+    ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, gfx::Point(0, 0),
+                               gfx::Point(0, 0), ui::EventTimeForNow(), 0, 0);
+    dialog_->ButtonPressed(dialog_->sink_buttons_for_test()[1], mouse_event);
+  }
+
+  std::unique_ptr<views::Widget> anchor_widget_;
+  MockCastDialogController controller_;
+  CastDialogView* dialog_ = nullptr;
+};
+
+TEST_F(CastDialogViewTest, ShowAndHideDialog) {
+  EXPECT_FALSE(CastDialogView::IsShowing());
+  EXPECT_EQ(nullptr, CastDialogView::GetCurrentDialogWidget());
+
+  EXPECT_CALL(controller_, AddObserver(_));
+  CastDialogView::ShowDialog(anchor_widget_->GetContentsView(), &controller_);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(CastDialogView::IsShowing());
+  EXPECT_NE(nullptr, CastDialogView::GetCurrentDialogWidget());
+
+  EXPECT_CALL(controller_, RemoveObserver(_));
+  CastDialogView::HideDialog();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(CastDialogView::IsShowing());
+  EXPECT_EQ(nullptr, CastDialogView::GetCurrentDialogWidget());
+}
+
+TEST_F(CastDialogViewTest, PopulateDialog) {
+  CastDialogModel model = CreateModelWithSinks({CreateAvailableSink()});
+  InitializeDialogWithModel(model);
+
+  EXPECT_TRUE(dialog_->ShouldShowCloseButton());
+  EXPECT_EQ(model.dialog_header, dialog_->GetWindowTitle());
+  EXPECT_EQ(ui::DIALOG_BUTTON_OK, dialog_->GetDialogButtons());
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_MEDIA_ROUTER_START_CASTING_BUTTON),
+            dialog_->GetDialogButtonLabel(ui::DIALOG_BUTTON_OK));
+}
+
+TEST_F(CastDialogViewTest, ChooseSinks) {
+  CastDialogModel model =
+      CreateModelWithSinks({CreateAvailableSink(), CreateConnectedSink()});
+  InitializeDialogWithModel(model);
+
+  // Activate the main action button. The sink at index 0 should be selected by
+  // default.
+  EXPECT_CALL(controller_, StartCasting(model.media_sinks[0].id, TAB_MIRROR));
+  dialog_->Accept();
+
+  // The label on the main action button should be updated when a different sink
+  // is chosen.
+  SelectSinkAtIndex(1);
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_MEDIA_ROUTER_STOP_CASTING_BUTTON),
+            dialog_->GetDialogButtonLabel(ui::DIALOG_BUTTON_OK));
+  EXPECT_CALL(controller_, StopCasting(model.media_sinks[0].route_id));
+  dialog_->Accept();
+}
+
+TEST_F(CastDialogViewTest, UpdateModel) {
+  CastDialogModel model =
+      CreateModelWithSinks({CreateAvailableSink(), CreateConnectedSink()});
+  InitializeDialogWithModel(model);
+  SelectSinkAtIndex(1);
+  model.media_sinks[1].state = UIMediaSinkState::AVAILABLE;
+  model.media_sinks[1].allowed_actions =
+      static_cast<int>(UICastAction::CAST_TAB);
+  dialog_->OnModelUpdated(model);
+
+  // Sink selection should be retained across a model update.
+  EXPECT_CALL(controller_, StartCasting(model.media_sinks[1].id, TAB_MIRROR));
+  dialog_->Accept();
+}
+
+}  // namespace media_router
diff --git a/chrome/browser/ui/webui/settings/chrome_cleanup_handler.cc b/chrome/browser/ui/webui/settings/chrome_cleanup_handler.cc
index 40ca7310..a982c678 100644
--- a/chrome/browser/ui/webui/settings/chrome_cleanup_handler.cc
+++ b/chrome/browser/ui/webui/settings/chrome_cleanup_handler.cc
@@ -21,6 +21,8 @@
 #include "chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.h"
 #include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/component_updater/pref_names.h"
+#include "components/prefs/pref_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_message_handler.h"
@@ -200,6 +202,13 @@
 
   // Send the current logs upload state.
   OnLogsEnabledChanged(controller_->logs_enabled());
+
+  // Inform the UI of the current chrome cleanup state.
+  bool is_managed = g_browser_process->local_state() &&
+                    g_browser_process->local_state()->IsManagedPreference(
+                        prefs::kSwReporterEnabled);
+  FireWebUIListener("chrome-cleanup-enabled-change", base::Value(is_managed),
+                    base::Value(controller_->IsAllowedByPolicy()));
 }
 
 void ChromeCleanupHandler::HandleStartScanning(const base::ListValue* args) {
@@ -207,6 +216,9 @@
   bool allow_logs_upload = false;
   args->GetBoolean(0, &allow_logs_upload);
 
+  // If this operation is not allowed the UI should be disabled.
+  CHECK(controller_->IsAllowedByPolicy());
+
   // The state is propagated to all open tabs and should be consistent.
   DCHECK_EQ(controller_->logs_enabled(), allow_logs_upload);
 
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler.cc b/chrome/browser/ui/webui/sync_internals_message_handler.cc
index bb154ad..9bd2b4a 100644
--- a/chrome/browser/ui/webui/sync_internals_message_handler.cc
+++ b/chrome/browser/ui/webui/sync_internals_message_handler.cc
@@ -17,6 +17,8 @@
 #include "chrome/browser/sync/user_event_service_factory.h"
 #include "chrome/common/channel_info.h"
 #include "components/browser_sync/profile_sync_service.h"
+#include "components/sync/base/enum_set.h"
+#include "components/sync/base/model_type.h"
 #include "components/sync/base/weak_handle.h"
 #include "components/sync/driver/about_sync_util.h"
 #include "components/sync/driver/sync_driver_switches.h"
@@ -130,6 +132,11 @@
                           base::Unretained(this)));
 
   web_ui()->RegisterMessageCallback(
+      syncer::sync_ui_util::kTriggerRefresh,
+      base::BindRepeating(&SyncInternalsMessageHandler::HandleTriggerRefresh,
+                          base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
       syncer::sync_ui_util::kGetAllNodes,
       base::BindRepeating(&SyncInternalsMessageHandler::HandleGetAllNodes,
                           base::Unretained(this)));
@@ -256,6 +263,18 @@
   user_event_service->RecordUserEvent(event_specifics);
 }
 
+void SyncInternalsMessageHandler::HandleTriggerRefresh(
+    const base::ListValue* args) {
+  SyncService* service = GetSyncService();
+  if (!service)
+    return;
+
+  // Only allowed to trigger refresh/schedule nudges for protocol types, things
+  // like PROXY_TABS are not allowed.
+  service->TriggerRefresh(syncer::Intersection(service->GetActiveDataTypes(),
+                                               syncer::ProtocolTypes()));
+}
+
 void SyncInternalsMessageHandler::OnReceivedAllNodes(
     int request_id,
     std::unique_ptr<ListValue> nodes) {
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler.h b/chrome/browser/ui/webui/sync_internals_message_handler.h
index 4c6f419..336aa635 100644
--- a/chrome/browser/ui/webui/sync_internals_message_handler.h
+++ b/chrome/browser/ui/webui/sync_internals_message_handler.h
@@ -68,6 +68,9 @@
   // Handler for writeUserEvent message.
   void HandleWriteUserEvent(const base::ListValue* args);
 
+  // Handler for triggerRefresh message.
+  void HandleTriggerRefresh(const base::ListValue* args);
+
   // syncer::JsEventHandler implementation.
   void HandleJsEvent(const std::string& name,
                      const syncer::JsEventDetails& details) override;
diff --git a/chrome/browser/vr/testapp/vr_test_context.cc b/chrome/browser/vr/testapp/vr_test_context.cc
index fdf2a6ef..5c9f0f02 100644
--- a/chrome/browser/vr/testapp/vr_test_context.cc
+++ b/chrome/browser/vr/testapp/vr_test_context.cc
@@ -62,7 +62,7 @@
 const float kVerticalScrollScaleFactor =
     -8.0f / ui::MouseWheelEvent::kWheelDelta;
 const float kHorizontalScrollScaleFactor =
-    60.0f / ui::MouseWheelEvent::kWheelDelta;
+    100.0f / ui::MouseWheelEvent::kWheelDelta;
 constexpr gfx::PointF kInitialTouchPosition = {0.5f, 0.5f};
 
 void RotateToward(const gfx::Vector3dF& fwd, gfx::Transform* transform) {
diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl
index a827b7c..24c7650 100644
--- a/chrome/common/extensions/api/file_manager_private.idl
+++ b/chrome/common/extensions/api/file_manager_private.idl
@@ -1078,7 +1078,8 @@
   static void isCrostiniEnabled(BooleanCallback callback);
 
   // Starts and mounts crostini container.
-  static void mountCrostiniContainer();
+  // |callback|
+  static void mountCrostiniContainer(BooleanCallback callback);
 };
 
 interface Events {
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index b20e8bee..2e60b5e 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -4246,6 +4246,7 @@
       "../browser/ui/views/harmony/layout_provider_unittest.cc",
       "../browser/ui/views/hover_button_unittest.cc",
       "../browser/ui/views/media_router/cast_dialog_sink_button_unittest.cc",
+      "../browser/ui/views/media_router/cast_dialog_view_unittest.cc",
       "../browser/ui/views/page_info/page_info_bubble_view_unittest.cc",
       "../browser/ui/views/payments/payment_request_item_list_unittest.cc",
       "../browser/ui/views/payments/validating_textfield_unittest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
index b852a0d..13ccfb9 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
@@ -50,6 +50,7 @@
 import org.chromium.chrome.test.util.MenuUtils;
 import org.chromium.chrome.test.util.NewTabPageTestUtils;
 import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.JavaScriptUtils;
 import org.chromium.content.browser.test.util.RenderProcessLimit;
@@ -631,6 +632,24 @@
         mSetActivity = chromeActivity;
     }
 
+    /**
+     * Waits for an Activity of the given class to be started.
+     * @return The Activity.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends ChromeActivity> T waitFor(final Class<T> expectedClass) {
+        final Activity[] holder = new Activity[1];
+        CriteriaHelper.pollUiThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                holder[0] = ApplicationStatus.getLastTrackedFocusedActivity();
+                return holder[0] != null && expectedClass.isAssignableFrom(holder[0].getClass())
+                        && ((ChromeActivity) holder[0]).getActivityTab() != null;
+            }
+        });
+        return (T) holder[0];
+    }
+
     private class ChromeUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
         @Override
         public void uncaughtException(Thread t, Throwable e) {
diff --git a/chrome/test/data/android/form.html b/chrome/test/data/android/form.html
new file mode 100644
index 0000000..7b99272
--- /dev/null
+++ b/chrome/test/data/android/form.html
@@ -0,0 +1,7 @@
+<html>
+  <body>
+    <form id="form" method="post">
+      <input id="post_button" type="submit">
+    </form>
+  </body>
+</html>
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index e95a5c03..8ab7fc2 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -13,6 +13,7 @@
     "md_bookmarks/md_bookmarks_focus_test.js",
     "md_history/md_history_focus_test.js",
     "settings/cr_settings_interactive_ui_tests.js",
+    "settings/settings_ui_browsertest.js",
   ]
 
   gen_include_files = [
@@ -99,7 +100,6 @@
     "settings/settings_idle_load_browsertest.js",
     "settings/settings_page_browsertest.js",
     "settings/settings_passwords_section_browsertest.js",
-    "settings/settings_ui_browsertest.js",
     "settings/site_settings_page_browsertest.js",
     "text_defaults_browsertest.js",
     "webui_resource_async_browsertest.js",
diff --git a/chrome/test/data/webui/cr_elements/cr_drawer_tests.js b/chrome/test/data/webui/cr_elements/cr_drawer_tests.js
index c3780e86..478d8c4 100644
--- a/chrome/test/data/webui/cr_elements/cr_drawer_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_drawer_tests.js
@@ -43,6 +43,13 @@
     });
   });
 
+  test('opened event', function() {
+    const drawer = createDrawer('ltr');
+    const whenOpen = test_util.eventToPromise('cr-drawer-opened', drawer);
+    drawer.openDrawer();
+    return whenOpen;
+  });
+
   test('align=ltr', function() {
     createDrawer('ltr').openDrawer();
     return test_util.eventToPromise('transitionend', drawer).then(() => {
diff --git a/chrome/test/data/webui/settings/controlled_radio_button_tests.js b/chrome/test/data/webui/settings/controlled_radio_button_tests.js
index 6b233be..e80cf624 100644
--- a/chrome/test/data/webui/settings/controlled_radio_button_tests.js
+++ b/chrome/test/data/webui/settings/controlled_radio_button_tests.js
@@ -24,8 +24,7 @@
     radioButton.set('pref.enforcement',
                     chrome.settingsPrivate.Enforcement.ENFORCED);
     Polymer.dom.flush();
-    // TODO(dbeam): rewrite this not to test private state (controlled_).
-    assertTrue(radioButton.controlled_);
+    assertTrue(radioButton.disabled);
     assertFalse(!!radioButton.$$('cr-policy-pref-indicator'));
 
     radioButton.set('name', 'true');
@@ -34,7 +33,7 @@
 
     radioButton.set('pref.enforcement', undefined);
     Polymer.dom.flush();
-    assertFalse(radioButton.controlled_);
+    assertFalse(radioButton.disabled);
     assertEquals('none',
                  radioButton.$$('cr-policy-pref-indicator').style.display);
   });
diff --git a/chrome/test/data/webui/settings/settings_ui_browsertest.js b/chrome/test/data/webui/settings/settings_ui_browsertest.js
index 7f56bc1..c12ea54 100644
--- a/chrome/test/data/webui/settings/settings_ui_browsertest.js
+++ b/chrome/test/data/webui/settings/settings_ui_browsertest.js
@@ -14,6 +14,11 @@
 
 SettingsUIBrowserTest.prototype = {
   __proto__: SettingsPageBrowserTest.prototype,
+
+  /** @override */
+  extraLibraries: SettingsPageBrowserTest.prototype.extraLibraries.concat([
+    'test_util.js',
+  ]),
 };
 
 // Times out on debug builders and may time out on memory bots because
@@ -21,12 +26,19 @@
 // and several times that in a Debug build. See https://crbug.com/558434
 // and http://crbug.com/711256.
 
-TEST_F('SettingsUIBrowserTest', 'DISABLED_All', function() {
+GEN('#if !defined(NDEBUG) || defined(OS_MACOSX)');
+GEN('#define MAYBE_All DISABLED_All');
+GEN('#else');
+GEN('#define MAYBE_All All');
+GEN('#endif');
+
+TEST_F('SettingsUIBrowserTest', 'MAYBE_All', function() {
   suite('settings-ui', function() {
     let toolbar;
     let ui;
 
     suiteSetup(function() {
+      testing.Test.disableAnimationsAndTransitions();
       ui = assert(document.querySelector('settings-ui'));
       ui.$.drawerTemplate.restamp = true;
     });
@@ -41,40 +53,32 @@
       assertTrue(toolbar.showMenu);
     });
 
-    test('app drawer', function(done) {
+    test('app drawer', function() {
       assertEquals(null, ui.$$('settings-menu'));
       const drawer = ui.$.drawer;
       assertFalse(!!drawer.open);
 
+      const whenDone = test_util.eventToPromise('cr-drawer-opened', drawer)
+          .then(function() {
+            const whenClosed = test_util.eventToPromise('open-changed', drawer);
+            drawer.closeDrawer();
+            return whenClosed;
+          })
+          .then(function(e) {
+            // Drawer is closed, but menu is still stamped so
+            // its contents remain visible as the drawer slides
+            // out.
+            assertFalse(e.detail.value);
+            assertTrue(!!ui.$$('settings-menu'));
+          });
       drawer.openDrawer();
-
       Polymer.dom.flush();
+
       // Validate that dialog is open and menu is shown so it will animate.
       assertTrue(drawer.open);
       assertTrue(!!ui.$$('settings-menu'));
 
-      // Close the dialog after it fully opens.
-      drawer.addEventListener('transitionend', function() {
-        if (drawer.classList.contains('opening')) {
-          // Click away from the drawer. MockInteractions don't expose a way to
-          // click at a specific location.
-          const midScreen = MockInteractions.middleOfNode(ui);
-          drawer.dispatchEvent(new MouseEvent('click', {
-            'bubbles': true,
-            'cancelable': true,
-            'clientX': midScreen.x,
-            'clientY': midScreen.y,
-          }));
-        }
-      });
-
-      drawer.addEventListener('close', function() {
-        // Drawer is closed, but menu is still stamped so its contents remain
-        // visible as the drawer slides out.
-        assertFalse(drawer.open);
-        assertTrue(!!ui.$$('settings-menu'));
-        done();
-      });
+      return whenDone;
     });
 
     test('advanced UIs stay in sync', function() {
@@ -121,6 +125,7 @@
     });
 
     test('search box initiated search propagates to URL', function() {
+      toolbar = /** @type {!CrToolbarElement} */ (ui.$$('cr-toolbar'));
       const searchField = /** @type {CrToolbarSearchFieldElement} */ (
           toolbar.getSearchField());
 
@@ -140,7 +145,7 @@
       assertEquals(value, settings.getQueryParameters().get('search'));
     });
 
-     test('whitespace only search query is ignored', function() {
+    test('whitespace only search query is ignored', function() {
       toolbar = /** @type {!CrToolbarElement} */ (ui.$$('cr-toolbar'));
       const searchField = /** @type {CrToolbarSearchFieldElement} */ (
           toolbar.getSearchField());
@@ -160,6 +165,23 @@
       urlParams = settings.getQueryParameters();
       assertFalse(urlParams.has('search'));
     });
+
+    test('find shortcut', function() {
+      document.body.focus();
+      assertTrue(ui.canHandleFindShortcut());
+
+      ui.handleFindShortcut();
+      assertTrue(ui.$$('cr-toolbar').getSearchField().isSearchFocused());
+
+      settings.navigateTo(settings.routes.RESET_DIALOG);
+      Polymer.dom.flush();
+
+      let dialog = assert(ui.querySelector(
+          '* /deep/ settings-reset-profile-dialog /deep/ cr-dialog'));
+      return test_util.whenAttributeIs(dialog, 'open', '').then(function() {
+        assertFalse(ui.canHandleFindShortcut());
+      });
+    });
   });
 
   mocha.run();
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index 6774ff1..f442eb9 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -140,6 +140,8 @@
     "cryptohome/system_salt_getter.h",
     "cryptohome/tpm_util.cc",
     "cryptohome/tpm_util.h",
+    "dbus/arc_appfuse_provider_client.cc",
+    "dbus/arc_appfuse_provider_client.h",
     "dbus/arc_midis_client.cc",
     "dbus/arc_midis_client.h",
     "dbus/arc_obb_mounter_client.cc",
@@ -179,6 +181,8 @@
     "dbus/debug_daemon_client.h",
     "dbus/easy_unlock_client.cc",
     "dbus/easy_unlock_client.h",
+    "dbus/fake_arc_appfuse_provider_client.cc",
+    "dbus/fake_arc_appfuse_provider_client.h",
     "dbus/fake_arc_midis_client.cc",
     "dbus/fake_arc_midis_client.h",
     "dbus/fake_arc_obb_mounter_client.cc",
diff --git a/chromeos/components/drivefs/BUILD.gn b/chromeos/components/drivefs/BUILD.gn
index 42adf7c..0821bcb5 100644
--- a/chromeos/components/drivefs/BUILD.gn
+++ b/chromeos/components/drivefs/BUILD.gn
@@ -19,8 +19,12 @@
     "//chromeos/components/drivefs/mojom",
     "//components/account_id",
     "//dbus",
+    "//google_apis",
     "//mojo/edk",
     "//mojo/public/cpp/bindings",
+    "//net",
+    "//services/identity/public/mojom",
+    "//services/service_manager/public/cpp",
   ]
   defines = [ "IS_DRIVEFS_IMPL" ]
 }
@@ -39,6 +43,10 @@
     "//chromeos:test_support",
     "//chromeos/components/drivefs/mojom",
     "//mojo/public/cpp/bindings",
+    "//net",
+    "//services/identity/public/mojom",
+    "//services/service_manager/public/cpp",
+    "//services/service_manager/public/cpp/test:test_support",
     "//testing/gmock",
     "//testing/gtest",
   ]
diff --git a/chromeos/components/drivefs/DEPS b/chromeos/components/drivefs/DEPS
index 348fd9f..aa94549 100644
--- a/chromeos/components/drivefs/DEPS
+++ b/chromeos/components/drivefs/DEPS
@@ -1,4 +1,6 @@
 include_rules = [
   "+mojo/edk/embedder",
   "+mojo/public",
+  "+services/identity/public",
+  "+services/service_manager/public",
 ]
diff --git a/chromeos/components/drivefs/drivefs_host.cc b/chromeos/components/drivefs/drivefs_host.cc
index 3a9fcfc..ca6559d 100644
--- a/chromeos/components/drivefs/drivefs_host.cc
+++ b/chromeos/components/drivefs/drivefs_host.cc
@@ -15,6 +15,8 @@
 #include "mojo/edk/embedder/scoped_platform_handle.h"
 #include "mojo/edk/embedder/transport_protocol.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "services/identity/public/mojom/constants.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 namespace drivefs {
 
@@ -22,15 +24,12 @@
 
 constexpr char kMountScheme[] = "drivefs://";
 constexpr char kDataPath[] = "GCache/v2";
+constexpr char kIdentityConsumerId[] = "drivefs";
 
 class MojoConnectionDelegateImpl : public DriveFsHost::MojoConnectionDelegate {
  public:
   MojoConnectionDelegateImpl() = default;
 
-  static std::unique_ptr<DriveFsHost::MojoConnectionDelegate> Create() {
-    return std::make_unique<MojoConnectionDelegateImpl>();
-  }
-
   mojom::DriveFsBootstrapPtrInfo InitializeMojoConnection() override {
     return mojom::DriveFsBootstrapPtrInfo(
         invitation_.AttachMessagePipe("drivefs-bootstrap"),
@@ -51,26 +50,35 @@
   DISALLOW_COPY_AND_ASSIGN(MojoConnectionDelegateImpl);
 };
 
-base::RepeatingCallback<std::unique_ptr<DriveFsHost::MojoConnectionDelegate>()>
-GetMojoConnectionDelegateFactoryOrDefault(
-    base::RepeatingCallback<
-        std::unique_ptr<DriveFsHost::MojoConnectionDelegate>()> factory) {
-  return factory ? factory
-                 : base::BindRepeating(&MojoConnectionDelegateImpl::Create);
+}  // namespace
+
+std::unique_ptr<OAuth2MintTokenFlow> DriveFsHost::Delegate::CreateMintTokenFlow(
+    OAuth2MintTokenFlow::Delegate* delegate,
+    const std::string& client_id,
+    const std::string& app_id,
+    const std::vector<std::string>& scopes) {
+  return std::make_unique<OAuth2MintTokenFlow>(
+      delegate, OAuth2MintTokenFlow::Parameters{
+                    app_id, client_id, scopes, kIdentityConsumerId,
+                    OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE});
 }
 
-}  // namespace
+std::unique_ptr<DriveFsHost::MojoConnectionDelegate>
+DriveFsHost::Delegate::CreateMojoConnectionDelegate() {
+  return std::make_unique<MojoConnectionDelegateImpl>();
+}
 
 // A container of state tied to a particular mounting of DriveFS. None of this
 // should be shared between mounts.
-class DriveFsHost::MountState {
+class DriveFsHost::MountState : public mojom::DriveFsDelegate,
+                                public OAuth2MintTokenFlow::Delegate {
  public:
   explicit MountState(DriveFsHost* host)
       : host_(host),
         mojo_connection_delegate_(
-            host_->mojo_connection_delegate_factory_.Run()),
+            host_->delegate_->CreateMojoConnectionDelegate()),
         pending_token_(base::UnguessableToken::Create()),
-        binding_(host_) {
+        binding_(this) {
     source_path_ = base::StrCat({kMountScheme, pending_token_.ToString(), "@",
                                  host_->profile_path_.Append(kDataPath)
                                      .Append(host_->account_id_.GetGaiaId())
@@ -96,7 +104,8 @@
                        base::Unretained(this)));
   }
 
-  ~MountState() {
+  ~MountState() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
     if (pending_token_) {
       PendingConnectionManager::Get().CancelExpectedOpenIpcChannel(
           pending_token_);
@@ -110,6 +119,7 @@
   // Accepts the mojo connection over |handle|, delegating to
   // |mojo_connection_delegate_|.
   void AcceptMojoConnection(base::ScopedFD handle) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
     DCHECK(pending_token_);
     pending_token_ = {};
     mojo_connection_delegate_->AcceptMojoConnection(std::move(handle));
@@ -121,6 +131,7 @@
       chromeos::disks::DiskMountManager::MountEvent event,
       chromeos::MountError error_code,
       const chromeos::disks::DiskMountManager::MountPointInfo& mount_info) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
     if (mount_info.source_path != source_path_ ||
         event != chromeos::disks::DiskMountManager::MOUNTING) {
       return true;
@@ -133,7 +144,59 @@
   }
 
  private:
-  // Owns this.
+  // mojom::DriveFsDelegate:
+  void GetAccessToken(const std::string& client_id,
+                      const std::string& app_id,
+                      const std::vector<std::string>& scopes,
+                      GetAccessTokenCallback callback) override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
+    if (get_access_token_callback_) {
+      std::move(callback).Run(mojom::AccessTokenStatus::kTransientError, "");
+      return;
+    }
+    DCHECK(!mint_token_flow_);
+    get_access_token_callback_ = std::move(callback);
+    mint_token_flow_ =
+        host_->delegate_->CreateMintTokenFlow(this, client_id, app_id, scopes);
+    DCHECK(mint_token_flow_);
+    host_->GetIdentityManager().GetAccessToken(
+        host_->account_id_.GetUserEmail(), {}, kIdentityConsumerId,
+        base::BindOnce(&DriveFsHost::MountState::GotChromeAccessToken,
+                       base::Unretained(this)));
+  }
+
+  void GotChromeAccessToken(const base::Optional<std::string>& access_token,
+                            base::Time expiration_time,
+                            const GoogleServiceAuthError& error) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
+    if (!access_token) {
+      OnMintTokenFailure(error);
+      return;
+    }
+    mint_token_flow_->Start(host_->delegate_->GetRequestContext(),
+                            *access_token);
+  }
+
+  // OAuth2MintTokenFlow::Delegate:
+  void OnMintTokenSuccess(const std::string& access_token,
+                          int time_to_live) override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
+    std::move(get_access_token_callback_)
+        .Run(mojom::AccessTokenStatus::kSuccess, access_token);
+    mint_token_flow_.reset();
+  }
+
+  void OnMintTokenFailure(const GoogleServiceAuthError& error) override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
+    std::move(get_access_token_callback_)
+        .Run(error.IsPersistentError()
+                 ? mojom::AccessTokenStatus::kAuthError
+                 : mojom::AccessTokenStatus::kTransientError,
+             "");
+    mint_token_flow_.reset();
+  }
+
+  // Owns |this|.
   DriveFsHost* const host_;
 
   const std::unique_ptr<DriveFsHost::MojoConnectionDelegate>
@@ -149,6 +212,12 @@
   // The path where DriveFS is mounted.
   std::string mount_path_;
 
+  // Pending callback for an in-flight GetAccessToken request.
+  GetAccessTokenCallback get_access_token_callback_;
+
+  // The mint token flow, if one is in flight.
+  std::unique_ptr<OAuth2MintTokenFlow> mint_token_flow_;
+
   // Mojo connections to the DriveFS process.
   mojom::DriveFsPtr drivefs_;
   mojo::Binding<mojom::DriveFsDelegate> binding_;
@@ -157,25 +226,22 @@
   DISALLOW_COPY_AND_ASSIGN(MountState);
 };
 
-DriveFsHost::DriveFsHost(
-    const base::FilePath& profile_path,
-    const AccountId& account_id,
-    base::RepeatingCallback<
-        std::unique_ptr<DriveFsHost::MojoConnectionDelegate>()>
-        mojo_connection_delegate_factory)
+DriveFsHost::DriveFsHost(const base::FilePath& profile_path,
+                         const AccountId& account_id,
+                         DriveFsHost::Delegate* delegate)
     : profile_path_(profile_path),
       account_id_(account_id),
-      mojo_connection_delegate_factory_(
-          GetMojoConnectionDelegateFactoryOrDefault(
-              std::move(mojo_connection_delegate_factory))) {
+      delegate_(delegate) {
   chromeos::disks::DiskMountManager::GetInstance()->AddObserver(this);
 }
 
 DriveFsHost::~DriveFsHost() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   chromeos::disks::DiskMountManager::GetInstance()->RemoveObserver(this);
 }
 
 bool DriveFsHost::Mount() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (mount_state_ || account_id_.GetAccountType() != AccountType::GOOGLE) {
     return false;
   }
@@ -184,21 +250,15 @@
 }
 
 void DriveFsHost::Unmount() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   mount_state_.reset();
 }
 
-void DriveFsHost::GetAccessToken(const std::string& client_id,
-                                 const std::string& app_id,
-                                 const std::vector<std::string>& scopes,
-                                 GetAccessTokenCallback callback) {
-  // TODO(crbug.com/823956): Implement this.
-  std::move(callback).Run(mojom::AccessTokenStatus::kAuthError, "");
-}
-
 void DriveFsHost::OnMountEvent(
     chromeos::disks::DiskMountManager::MountEvent event,
     chromeos::MountError error_code,
     const chromeos::disks::DiskMountManager::MountPointInfo& mount_info) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!mount_state_) {
     return;
   }
@@ -207,4 +267,13 @@
   }
 }
 
+identity::mojom::IdentityManager& DriveFsHost::GetIdentityManager() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!identity_manager_) {
+    delegate_->GetConnector()->BindInterface(
+        identity::mojom::kServiceName, mojo::MakeRequest(&identity_manager_));
+  }
+  return *identity_manager_;
+}
+
 }  // namespace drivefs
diff --git a/chromeos/components/drivefs/drivefs_host.h b/chromeos/components/drivefs/drivefs_host.h
index 2fe2450..57879ca 100644
--- a/chromeos/components/drivefs/drivefs_host.h
+++ b/chromeos/components/drivefs/drivefs_host.h
@@ -16,6 +16,16 @@
 #include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
 #include "chromeos/disks/disk_mount_manager.h"
 #include "components/account_id/account_id.h"
+#include "google_apis/gaia/oauth2_mint_token_flow.h"
+#include "services/identity/public/mojom/identity_manager.mojom.h"
+
+namespace net {
+class URLRequestContextGetter;
+}  // namespace net
+
+namespace service_manager {
+class Connector;
+}  // namespace service_manager
 
 namespace drivefs {
 
@@ -23,9 +33,10 @@
 // mounting and unmounting, it also bridges between the DriveFS process and the
 // file manager.
 class COMPONENT_EXPORT(DRIVEFS) DriveFsHost
-    : public mojom::DriveFsDelegate,
-      public chromeos::disks::DiskMountManager::Observer {
+    : public chromeos::disks::DiskMountManager::Observer {
  public:
+  // Public for overriding in tests. A default implementation is used under
+  // normal conditions.
   class MojoConnectionDelegate {
    public:
     virtual ~MojoConnectionDelegate() = default;
@@ -38,10 +49,28 @@
     virtual void AcceptMojoConnection(base::ScopedFD handle) = 0;
   };
 
+  class Delegate {
+   public:
+    Delegate() = default;
+    virtual ~Delegate() = default;
+
+    virtual net::URLRequestContextGetter* GetRequestContext() = 0;
+    virtual service_manager::Connector* GetConnector() = 0;
+    virtual std::unique_ptr<OAuth2MintTokenFlow> CreateMintTokenFlow(
+        OAuth2MintTokenFlow::Delegate* delegate,
+        const std::string& client_id,
+        const std::string& app_id,
+        const std::vector<std::string>& scopes);
+    virtual std::unique_ptr<MojoConnectionDelegate>
+    CreateMojoConnectionDelegate();
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Delegate);
+  };
+
   DriveFsHost(const base::FilePath& profile_path,
               const AccountId& account,
-              base::RepeatingCallback<std::unique_ptr<MojoConnectionDelegate>()>
-                  mojo_connection_delegate_factory = {});
+              Delegate* delegate);
   ~DriveFsHost() override;
 
   // Mount DriveFS.
@@ -53,31 +82,31 @@
  private:
   class MountState;
 
-  // mojom::DriveFsDelegate:
-  void GetAccessToken(const std::string& client_id,
-                      const std::string& app_id,
-                      const std::vector<std::string>& scopes,
-                      GetAccessTokenCallback callback) override;
-
   // DiskMountManager::Observer:
   void OnMountEvent(chromeos::disks::DiskMountManager::MountEvent event,
                     chromeos::MountError error_code,
                     const chromeos::disks::DiskMountManager::MountPointInfo&
                         mount_info) override;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  // Returns the connection to the identity service, connecting lazily.
+  identity::mojom::IdentityManager& GetIdentityManager();
+
   // The path to the user's profile.
   const base::FilePath profile_path_;
 
   // The user whose DriveFS instance |this| is host to.
   const AccountId account_id_;
 
-  // A callback used to create mojo connection delegates.
-  const base::RepeatingCallback<std::unique_ptr<MojoConnectionDelegate>()>
-      mojo_connection_delegate_factory_;
+  Delegate* const delegate_;
 
   // State specific to the current mount, or null if not mounted.
   std::unique_ptr<MountState> mount_state_;
 
+  // The connection to the identity service. Access via |GetIdentityManager()|.
+  identity::mojom::IdentityManagerPtr identity_manager_;
+
   DISALLOW_COPY_AND_ASSIGN(DriveFsHost);
 };
 
diff --git a/chromeos/components/drivefs/drivefs_host_unittest.cc b/chromeos/components/drivefs/drivefs_host_unittest.cc
index 0f860f9..b6ef23d 100644
--- a/chromeos/components/drivefs/drivefs_host_unittest.cc
+++ b/chromeos/components/drivefs/drivefs_host_unittest.cc
@@ -15,6 +15,11 @@
 #include "chromeos/components/drivefs/pending_connection_manager.h"
 #include "chromeos/disks/mock_disk_mount_manager.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/cpp/service.h"
+#include "services/service_manager/public/cpp/test/test_connector_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace drivefs {
@@ -37,8 +42,162 @@
 
  private:
   mojom::DriveFsBootstrapPtrInfo pending_bootstrap_;
+};
 
-  DISALLOW_COPY_AND_ASSIGN(TestingMojoConnectionDelegate);
+class ForwardingOAuth2MintTokenFlow;
+
+ACTION_P(SucceedMintToken, token) {
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindLambdaForTesting([=] { arg0->OnMintTokenSuccess(token, 0); }));
+}
+
+ACTION_P(FailMintToken, error) {
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindLambdaForTesting([=] {
+        arg0->OnMintTokenFailure(GoogleServiceAuthError(error));
+      }));
+}
+
+class MockOAuth2MintTokenFlow {
+ public:
+  MockOAuth2MintTokenFlow() = default;
+
+  void ExpectStartAndSucceed(const std::string& expected_token,
+                             const std::string& token_to_return) {
+    EXPECT_CALL(*this, Start(_, expected_token))
+        .WillOnce(SucceedMintToken(token_to_return));
+  }
+
+  void ExpectStartAndFail(const std::string& expected_token,
+                          GoogleServiceAuthError::State error) {
+    EXPECT_CALL(*this, Start(_, expected_token)).WillOnce(FailMintToken(error));
+  }
+
+  void ExpectNoStartCalls() { EXPECT_CALL(*this, Start(_, _)).Times(0); }
+
+ private:
+  friend class ForwardingOAuth2MintTokenFlow;
+  MOCK_METHOD2(Start,
+               void(OAuth2MintTokenFlow::Delegate* delegate,
+                    const std::string& access_token));
+
+  DISALLOW_COPY_AND_ASSIGN(MockOAuth2MintTokenFlow);
+};
+
+class ForwardingOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
+ public:
+  ForwardingOAuth2MintTokenFlow(OAuth2MintTokenFlow::Delegate* delegate,
+                                MockOAuth2MintTokenFlow* mock)
+      : OAuth2MintTokenFlow(delegate, {}), delegate_(delegate), mock_(mock) {}
+
+  void Start(net::URLRequestContextGetter* context_getter,
+             const std::string& access_token) override {
+    EXPECT_EQ(nullptr, context_getter);
+    mock_->Start(delegate_, access_token);
+  }
+
+ private:
+  Delegate* const delegate_;
+  MockOAuth2MintTokenFlow* mock_;
+};
+
+class TestingDriveFsHostDelegate : public DriveFsHost::Delegate {
+ public:
+  explicit TestingDriveFsHostDelegate(
+      std::unique_ptr<service_manager::Connector> connector)
+      : connector_(std::move(connector)) {}
+
+  MockOAuth2MintTokenFlow& mock_flow() { return mock_flow_; }
+
+  void set_pending_bootstrap(mojom::DriveFsBootstrapPtrInfo pending_bootstrap) {
+    pending_bootstrap_ = std::move(pending_bootstrap);
+  }
+
+ private:
+  // DriveFsHost::Delegate:
+  net::URLRequestContextGetter* GetRequestContext() override { return nullptr; }
+  service_manager::Connector* GetConnector() override {
+    return connector_.get();
+  }
+  std::unique_ptr<OAuth2MintTokenFlow> CreateMintTokenFlow(
+      OAuth2MintTokenFlow::Delegate* delegate,
+      const std::string& client_id,
+      const std::string& app_id,
+      const std::vector<std::string>& scopes) override {
+    EXPECT_EQ("client ID", client_id);
+    EXPECT_EQ("app ID", app_id);
+    EXPECT_EQ((std::vector<std::string>{"scope1", "scope2"}), scopes);
+    return std::make_unique<ForwardingOAuth2MintTokenFlow>(delegate,
+                                                           &mock_flow_);
+  }
+
+  std::unique_ptr<DriveFsHost::MojoConnectionDelegate>
+  CreateMojoConnectionDelegate() override {
+    DCHECK(pending_bootstrap_);
+    return std::make_unique<TestingMojoConnectionDelegate>(
+        std::move(pending_bootstrap_));
+  }
+
+  std::unique_ptr<service_manager::Connector> connector_;
+  MockOAuth2MintTokenFlow mock_flow_;
+  mojom::DriveFsBootstrapPtrInfo pending_bootstrap_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestingDriveFsHostDelegate);
+};
+
+class MockIdentityManager {
+ public:
+  MOCK_METHOD3(
+      GetAccessToken,
+      std::pair<base::Optional<std::string>, GoogleServiceAuthError::State>(
+          const std::string& account_id,
+          const ::identity::ScopeSet& scopes,
+          const std::string& consumer_id));
+};
+
+class FakeIdentityService
+    : public identity::mojom::IdentityManagerInterceptorForTesting,
+      public service_manager::Service {
+ public:
+  explicit FakeIdentityService(MockIdentityManager* mock) : mock_(mock) {
+    binder_registry_.AddInterface(
+        base::BindRepeating(&FakeIdentityService::BindIdentityManagerRequest,
+                            base::Unretained(this)));
+  }
+
+ private:
+  void OnBindInterface(const service_manager::BindSourceInfo& source,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override {
+    binder_registry_.BindInterface(interface_name, std::move(interface_pipe));
+  }
+
+  void BindIdentityManagerRequest(
+      identity::mojom::IdentityManagerRequest request) {
+    bindings_.AddBinding(this, std::move(request));
+  }
+
+  // identity::mojom::IdentityManagerInterceptorForTesting overrides:
+  void GetAccessToken(const std::string& account_id,
+                      const ::identity::ScopeSet& scopes,
+                      const std::string& consumer_id,
+                      GetAccessTokenCallback callback) override {
+    auto result = mock_->GetAccessToken(account_id, scopes, consumer_id);
+    std::move(callback).Run(std::move(result.first), base::Time::Now(),
+                            GoogleServiceAuthError(result.second));
+  }
+
+  IdentityManager* GetForwardingInterface() override {
+    NOTREACHED();
+    return nullptr;
+  }
+
+  MockIdentityManager* const mock_;
+  service_manager::BinderRegistry binder_registry_;
+  mojo::BindingSet<identity::mojom::IdentityManager> bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeIdentityService);
 };
 
 class DriveFsHostTest : public ::testing::Test,
@@ -56,11 +215,13 @@
     disk_manager_ = new chromeos::disks::MockDiskMountManager;
     // Takes ownership of |disk_manager_|.
     chromeos::disks::DiskMountManager::InitializeForTesting(disk_manager_);
-
-    host_ = std::make_unique<DriveFsHost>(
-        profile_path_, account_id_,
-        base::BindRepeating(&DriveFsHostTest::CreateMojoConnectionDelegate,
-                            base::Unretained(this)));
+    connector_factory_ =
+        service_manager::TestConnectorFactory::CreateForUniqueService(
+            std::make_unique<FakeIdentityService>(&mock_identity_manager_));
+    host_delegate_ = std::make_unique<TestingDriveFsHostDelegate>(
+        connector_factory_->CreateConnector());
+    host_ = std::make_unique<DriveFsHost>(profile_path_, account_id_,
+                                          host_delegate_.get());
   }
 
   void TearDown() override {
@@ -69,13 +230,6 @@
     chromeos::disks::DiskMountManager::Shutdown();
   }
 
-  std::unique_ptr<DriveFsHost::MojoConnectionDelegate>
-  CreateMojoConnectionDelegate() {
-    DCHECK(pending_bootstrap_);
-    return std::make_unique<TestingMojoConnectionDelegate>(
-        std::move(pending_bootstrap_));
-  }
-
   void DispatchMountEvent(
       chromeos::disks::DiskMountManager::MountEvent event,
       chromeos::MountError error_code,
@@ -96,7 +250,7 @@
 
     mojom::DriveFsBootstrapPtrInfo bootstrap;
     bootstrap_binding_.Bind(mojo::MakeRequest(&bootstrap));
-    pending_bootstrap_ = std::move(bootstrap);
+    host_delegate_->set_pending_bootstrap(std::move(bootstrap));
 
     EXPECT_TRUE(host_->Mount());
     testing::Mock::VerifyAndClear(&disk_manager_);
@@ -138,14 +292,15 @@
   base::test::ScopedTaskEnvironment task_environment_;
   AccountId account_id_;
   chromeos::disks::MockDiskMountManager* disk_manager_;
+  MockIdentityManager mock_identity_manager_;
+  std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
+  std::unique_ptr<TestingDriveFsHostDelegate> host_delegate_;
   std::unique_ptr<DriveFsHost> host_;
 
   mojo::Binding<mojom::DriveFsBootstrap> bootstrap_binding_;
   mojo::Binding<mojom::DriveFs> binding_;
   mojom::DriveFsDelegatePtr delegate_ptr_;
 
-  mojom::DriveFsBootstrapPtrInfo pending_bootstrap_;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(DriveFsHostTest);
 };
@@ -240,13 +395,109 @@
 TEST_F(DriveFsHostTest, NonGaiaAccount) {
   EXPECT_CALL(*disk_manager_, MountPath(_, _, _, _, _)).Times(0);
   AccountId non_gaia_account = AccountId::FromUserEmail("test2@example.com");
-  host_ = std::make_unique<DriveFsHost>(profile_path_, non_gaia_account);
+  host_ =
+      std::make_unique<DriveFsHost>(profile_path_, non_gaia_account, nullptr);
   EXPECT_FALSE(host_->Mount());
 }
 
-TEST_F(DriveFsHostTest, GetAccessToken) {
+TEST_F(DriveFsHostTest, GetAccessToken_Success) {
   ASSERT_NO_FATAL_FAILURE(DoMount());
 
+  EXPECT_CALL(mock_identity_manager_,
+              GetAccessToken("test@example.com", _, "drivefs"))
+      .WillOnce(testing::Return(
+          std::make_pair("chrome token", GoogleServiceAuthError::NONE)));
+  host_delegate_->mock_flow().ExpectStartAndSucceed("chrome token",
+                                                    "auth token");
+
+  base::RunLoop run_loop;
+  auto quit_closure = run_loop.QuitClosure();
+  delegate_ptr_->GetAccessToken(
+      "client ID", "app ID", {"scope1", "scope2"},
+      base::BindLambdaForTesting(
+          [&](mojom::AccessTokenStatus status, const std::string& token) {
+            EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
+            EXPECT_EQ("auth token", token);
+            std::move(quit_closure).Run();
+          }));
+  run_loop.Run();
+}
+
+TEST_F(DriveFsHostTest, GetAccessToken_ParallelRequests) {
+  ASSERT_NO_FATAL_FAILURE(DoMount());
+
+  base::RunLoop run_loop;
+  auto quit_closure = run_loop.QuitClosure();
+  delegate_ptr_->GetAccessToken(
+      "client ID", "app ID", {"scope1", "scope2"},
+      base::BindOnce(
+          [](mojom::AccessTokenStatus status, const std::string& token) {
+            FAIL() << "Unexpected callback";
+          }));
+  delegate_ptr_->GetAccessToken(
+      "client ID", "app ID", {"scope1", "scope2"},
+      base::BindLambdaForTesting(
+          [&](mojom::AccessTokenStatus status, const std::string& token) {
+            EXPECT_EQ(mojom::AccessTokenStatus::kTransientError, status);
+            EXPECT_TRUE(token.empty());
+            std::move(quit_closure).Run();
+          }));
+  run_loop.Run();
+}
+
+TEST_F(DriveFsHostTest, GetAccessToken_SequentialRequests) {
+  ASSERT_NO_FATAL_FAILURE(DoMount());
+
+  for (int i = 0; i < 3; ++i) {
+    EXPECT_CALL(mock_identity_manager_,
+                GetAccessToken("test@example.com", _, "drivefs"))
+        .WillOnce(testing::Return(
+            std::make_pair("chrome token", GoogleServiceAuthError::NONE)));
+    host_delegate_->mock_flow().ExpectStartAndSucceed("chrome token",
+                                                      "auth token");
+
+    base::RunLoop run_loop;
+    auto quit_closure = run_loop.QuitClosure();
+    delegate_ptr_->GetAccessToken(
+        "client ID", "app ID", {"scope1", "scope2"},
+        base::BindLambdaForTesting(
+            [&](mojom::AccessTokenStatus status, const std::string& token) {
+              EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
+              EXPECT_EQ("auth token", token);
+              std::move(quit_closure).Run();
+            }));
+    run_loop.Run();
+  }
+  for (int i = 0; i < 3; ++i) {
+    EXPECT_CALL(mock_identity_manager_,
+                GetAccessToken("test@example.com", _, "drivefs"))
+        .WillOnce(testing::Return(std::make_pair(
+            base::nullopt, GoogleServiceAuthError::ACCOUNT_DISABLED)));
+    host_delegate_->mock_flow().ExpectNoStartCalls();
+
+    base::RunLoop run_loop;
+    auto quit_closure = run_loop.QuitClosure();
+    delegate_ptr_->GetAccessToken(
+        "client ID", "app ID", {"scope1", "scope2"},
+        base::BindLambdaForTesting(
+            [&](mojom::AccessTokenStatus status, const std::string& token) {
+              EXPECT_EQ(mojom::AccessTokenStatus::kAuthError, status);
+              EXPECT_TRUE(token.empty());
+              std::move(quit_closure).Run();
+            }));
+    run_loop.Run();
+  }
+}
+
+TEST_F(DriveFsHostTest, GetAccessToken_GetAccessTokenFailure_Permanent) {
+  ASSERT_NO_FATAL_FAILURE(DoMount());
+
+  EXPECT_CALL(mock_identity_manager_,
+              GetAccessToken("test@example.com", _, "drivefs"))
+      .WillOnce(testing::Return(std::make_pair(
+          base::nullopt, GoogleServiceAuthError::ACCOUNT_DISABLED)));
+  host_delegate_->mock_flow().ExpectNoStartCalls();
+
   base::RunLoop run_loop;
   auto quit_closure = run_loop.QuitClosure();
   delegate_ptr_->GetAccessToken(
@@ -260,5 +511,73 @@
   run_loop.Run();
 }
 
+TEST_F(DriveFsHostTest, GetAccessToken_GetAccessTokenFailure_Transient) {
+  ASSERT_NO_FATAL_FAILURE(DoMount());
+
+  EXPECT_CALL(mock_identity_manager_,
+              GetAccessToken("test@example.com", _, "drivefs"))
+      .WillOnce(testing::Return(std::make_pair(
+          base::nullopt, GoogleServiceAuthError::SERVICE_UNAVAILABLE)));
+  host_delegate_->mock_flow().ExpectNoStartCalls();
+
+  base::RunLoop run_loop;
+  auto quit_closure = run_loop.QuitClosure();
+  delegate_ptr_->GetAccessToken(
+      "client ID", "app ID", {"scope1", "scope2"},
+      base::BindLambdaForTesting(
+          [&](mojom::AccessTokenStatus status, const std::string& token) {
+            EXPECT_EQ(mojom::AccessTokenStatus::kTransientError, status);
+            EXPECT_TRUE(token.empty());
+            std::move(quit_closure).Run();
+          }));
+  run_loop.Run();
+}
+
+TEST_F(DriveFsHostTest, GetAccessToken_MintTokenFailure_Permanent) {
+  ASSERT_NO_FATAL_FAILURE(DoMount());
+
+  EXPECT_CALL(mock_identity_manager_,
+              GetAccessToken("test@example.com", _, "drivefs"))
+      .WillOnce(testing::Return(
+          std::make_pair("chrome token", GoogleServiceAuthError::NONE)));
+  host_delegate_->mock_flow().ExpectStartAndFail(
+      "chrome token", GoogleServiceAuthError::ACCOUNT_DISABLED);
+
+  base::RunLoop run_loop;
+  auto quit_closure = run_loop.QuitClosure();
+  delegate_ptr_->GetAccessToken(
+      "client ID", "app ID", {"scope1", "scope2"},
+      base::BindLambdaForTesting(
+          [&](mojom::AccessTokenStatus status, const std::string& token) {
+            EXPECT_EQ(mojom::AccessTokenStatus::kAuthError, status);
+            EXPECT_TRUE(token.empty());
+            std::move(quit_closure).Run();
+          }));
+  run_loop.Run();
+}
+
+TEST_F(DriveFsHostTest, GetAccessToken_MintTokenFailure_Transient) {
+  ASSERT_NO_FATAL_FAILURE(DoMount());
+
+  EXPECT_CALL(mock_identity_manager_,
+              GetAccessToken("test@example.com", _, "drivefs"))
+      .WillOnce(testing::Return(
+          std::make_pair("chrome token", GoogleServiceAuthError::NONE)));
+  host_delegate_->mock_flow().ExpectStartAndFail(
+      "chrome token", GoogleServiceAuthError::SERVICE_UNAVAILABLE);
+
+  base::RunLoop run_loop;
+  auto quit_closure = run_loop.QuitClosure();
+  delegate_ptr_->GetAccessToken(
+      "client ID", "app ID", {"scope1", "scope2"},
+      base::BindLambdaForTesting(
+          [&](mojom::AccessTokenStatus status, const std::string& token) {
+            EXPECT_EQ(mojom::AccessTokenStatus::kTransientError, status);
+            EXPECT_TRUE(token.empty());
+            std::move(quit_closure).Run();
+          }));
+  run_loop.Run();
+}
+
 }  // namespace
 }  // namespace drivefs
diff --git a/chromeos/dbus/arc_appfuse_provider_client.cc b/chromeos/dbus/arc_appfuse_provider_client.cc
new file mode 100644
index 0000000..6f2c52e
--- /dev/null
+++ b/chromeos/dbus/arc_appfuse_provider_client.cc
@@ -0,0 +1,122 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/dbus/arc_appfuse_provider_client.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "dbus/object_proxy.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+namespace {
+
+class ArcAppfuseProviderClientImpl : public ArcAppfuseProviderClient {
+ public:
+  ArcAppfuseProviderClientImpl() : weak_ptr_factory_(this) {}
+  ~ArcAppfuseProviderClientImpl() override = default;
+
+  // ArcAppfuseProviderClient override:
+  void Mount(uint32_t uid,
+             int32_t mount_id,
+             DBusMethodCallback<base::ScopedFD> callback) override {
+    dbus::MethodCall method_call(arc::appfuse::kArcAppfuseProviderInterface,
+                                 arc::appfuse::kMountMethod);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendUint32(uid);
+    writer.AppendInt32(mount_id);
+    proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&ArcAppfuseProviderClientImpl::OnFDMethod,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
+  void Unmount(uint32_t uid,
+               int32_t mount_id,
+               VoidDBusMethodCallback callback) override {
+    dbus::MethodCall method_call(arc::appfuse::kArcAppfuseProviderInterface,
+                                 arc::appfuse::kUnmountMethod);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendUint32(uid);
+    writer.AppendInt32(mount_id);
+    proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&ArcAppfuseProviderClientImpl::OnVoidDBusMethod,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
+  void OpenFile(uint32_t uid,
+                int32_t mount_id,
+                int32_t file_id,
+                int32_t flags,
+                DBusMethodCallback<base::ScopedFD> callback) override {
+    dbus::MethodCall method_call(arc::appfuse::kArcAppfuseProviderInterface,
+                                 arc::appfuse::kOpenFileMethod);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendUint32(uid);
+    writer.AppendInt32(mount_id);
+    writer.AppendInt32(file_id);
+    writer.AppendInt32(flags);
+    proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&ArcAppfuseProviderClientImpl::OnFDMethod,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
+ protected:
+  // DBusClient override.
+  void Init(dbus::Bus* bus) override {
+    proxy_ = bus->GetObjectProxy(
+        arc::appfuse::kArcAppfuseProviderServiceName,
+        dbus::ObjectPath(arc::appfuse::kArcAppfuseProviderServicePath));
+  }
+
+ private:
+  // Runs the callback with the method call result.
+  void OnVoidDBusMethod(VoidDBusMethodCallback callback,
+                        dbus::Response* response) {
+    std::move(callback).Run(response != nullptr);
+  }
+
+  void OnFDMethod(DBusMethodCallback<base::ScopedFD> callback,
+                  dbus::Response* response) {
+    if (!response) {
+      std::move(callback).Run(base::nullopt);
+      return;
+    }
+    dbus::MessageReader reader(response);
+    base::ScopedFD fd;
+    if (!reader.PopFileDescriptor(&fd)) {
+      LOG(ERROR) << "Failed to pop FD.";
+      std::move(callback).Run(base::nullopt);
+      return;
+    }
+    std::move(callback).Run(std::move(fd));
+  }
+
+  dbus::ObjectProxy* proxy_ = nullptr;
+
+  base::WeakPtrFactory<ArcAppfuseProviderClientImpl> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAppfuseProviderClientImpl);
+};
+
+}  // namespace
+
+ArcAppfuseProviderClient::ArcAppfuseProviderClient() = default;
+
+ArcAppfuseProviderClient::~ArcAppfuseProviderClient() = default;
+
+// static
+std::unique_ptr<ArcAppfuseProviderClient> ArcAppfuseProviderClient::Create() {
+  return std::make_unique<ArcAppfuseProviderClientImpl>();
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/arc_appfuse_provider_client.h b/chromeos/dbus/arc_appfuse_provider_client.h
new file mode 100644
index 0000000..6d190d38
--- /dev/null
+++ b/chromeos/dbus/arc_appfuse_provider_client.h
@@ -0,0 +1,54 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_ARC_APPFUSE_PROVIDER_CLIENT_H_
+#define CHROMEOS_DBUS_ARC_APPFUSE_PROVIDER_CLIENT_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/dbus_client.h"
+#include "chromeos/dbus/dbus_method_call_status.h"
+
+#include "base/files/scoped_file.h"
+
+namespace chromeos {
+
+// ArcAppfuseProviderClient is used to communicate with the ArcAppfuseProvider
+// service which provides ProxyFileDescriptor (aka appfuse) feature for ARC. All
+// methods should be called from the origin thread (UI thread) which initializes
+// the DBusThreadManager instance.
+class CHROMEOS_EXPORT ArcAppfuseProviderClient : public DBusClient {
+ public:
+  ArcAppfuseProviderClient();
+  ~ArcAppfuseProviderClient() override;
+
+  // Factory function, creates a new instance.
+  // For normal usage, access the singleton via DBusThreadManager::Get().
+  static std::unique_ptr<ArcAppfuseProviderClient> Create();
+
+  // Mounts a new appfuse file system and returns a filtered /dev/fuse FD
+  // associated with the mounted file system.
+  virtual void Mount(uint32_t uid,
+                     int32_t mount_id,
+                     DBusMethodCallback<base::ScopedFD> callback) = 0;
+
+  // Unmounts the specified appfuse file system.
+  virtual void Unmount(uint32_t uid,
+                       int32_t mount_id,
+                       VoidDBusMethodCallback callback) = 0;
+
+  // Opens a file under the specified appfuse file system.
+  virtual void OpenFile(uint32_t uid,
+                        int32_t mount_id,
+                        int32_t file_id,
+                        int32_t flags,
+                        DBusMethodCallback<base::ScopedFD> callback) = 0;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_ARC_APPFUSE_PROVIDER_CLIENT_H_
diff --git a/chromeos/dbus/dbus_clients_browser.cc b/chromeos/dbus/dbus_clients_browser.cc
index 3b047d89..6e974c9 100644
--- a/chromeos/dbus/dbus_clients_browser.cc
+++ b/chromeos/dbus/dbus_clients_browser.cc
@@ -5,6 +5,7 @@
 #include "chromeos/dbus/dbus_clients_browser.h"
 
 #include "base/logging.h"
+#include "chromeos/dbus/arc_appfuse_provider_client.h"
 #include "chromeos/dbus/arc_midis_client.h"
 #include "chromeos/dbus/arc_obb_mounter_client.h"
 #include "chromeos/dbus/arc_oemcrypto_client.h"
@@ -15,6 +16,7 @@
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/debug_daemon_client.h"
 #include "chromeos/dbus/easy_unlock_client.h"
+#include "chromeos/dbus/fake_arc_appfuse_provider_client.h"
 #include "chromeos/dbus/fake_arc_midis_client.h"
 #include "chromeos/dbus/fake_arc_obb_mounter_client.h"
 #include "chromeos/dbus/fake_arc_oemcrypto_client.h"
@@ -38,6 +40,13 @@
 namespace chromeos {
 
 DBusClientsBrowser::DBusClientsBrowser(bool use_real_clients) {
+  if (use_real_clients) {
+    arc_appfuse_provider_client_ = ArcAppfuseProviderClient::Create();
+  } else {
+    arc_appfuse_provider_client_ =
+        std::make_unique<FakeArcAppfuseProviderClient>();
+  }
+
   if (use_real_clients)
     arc_midis_client_ = ArcMidisClient::Create();
   else
diff --git a/chromeos/dbus/dbus_clients_browser.h b/chromeos/dbus/dbus_clients_browser.h
index f3f4ac4..f51ff2b7 100644
--- a/chromeos/dbus/dbus_clients_browser.h
+++ b/chromeos/dbus/dbus_clients_browser.h
@@ -16,6 +16,7 @@
 
 namespace chromeos {
 
+class ArcAppfuseProviderClient;
 class ArcMidisClient;
 class ArcObbMounterClient;
 class ArcOemCryptoClient;
@@ -46,6 +47,7 @@
   friend class DBusThreadManager;
   friend class DBusThreadManagerSetter;
 
+  std::unique_ptr<ArcAppfuseProviderClient> arc_appfuse_provider_client_;
   std::unique_ptr<ArcMidisClient> arc_midis_client_;
   std::unique_ptr<ArcObbMounterClient> arc_obb_mounter_client_;
   std::unique_ptr<ArcOemCryptoClient> arc_oemcrypto_client_;
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc
index e395a55d..fa171e2 100644
--- a/chromeos/dbus/dbus_thread_manager.cc
+++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -116,6 +116,11 @@
   return system_bus_.get();
 }
 
+ArcAppfuseProviderClient* DBusThreadManager::GetArcAppfuseProviderClient() {
+  return clients_browser_ ? clients_browser_->arc_appfuse_provider_client_.get()
+                          : nullptr;
+}
+
 ArcMidisClient* DBusThreadManager::GetArcMidisClient() {
   return clients_browser_ ? clients_browser_->arc_midis_client_.get() : nullptr;
 }
diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h
index 54e092b..7f48c33 100644
--- a/chromeos/dbus/dbus_thread_manager.h
+++ b/chromeos/dbus/dbus_thread_manager.h
@@ -24,6 +24,7 @@
 namespace chromeos {
 
 // Style Note: Clients are sorted by names.
+class ArcAppfuseProviderClient;
 class ArcMidisClient;
 class ArcObbMounterClient;
 class ArcOemCryptoClient;
@@ -130,6 +131,7 @@
   // pointers after DBusThreadManager has been shut down.
   // TODO(jamescook): Replace this with calls to FooClient::Get().
   // http://crbug.com/647367
+  ArcAppfuseProviderClient* GetArcAppfuseProviderClient();
   ArcMidisClient* GetArcMidisClient();
   ArcObbMounterClient* GetArcObbMounterClient();
   ArcOemCryptoClient* GetArcOemCryptoClient();
diff --git a/chromeos/dbus/fake_arc_appfuse_provider_client.cc b/chromeos/dbus/fake_arc_appfuse_provider_client.cc
new file mode 100644
index 0000000..ae79d856
--- /dev/null
+++ b/chromeos/dbus/fake_arc_appfuse_provider_client.cc
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/dbus/fake_arc_appfuse_provider_client.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace chromeos {
+
+FakeArcAppfuseProviderClient::FakeArcAppfuseProviderClient() = default;
+
+FakeArcAppfuseProviderClient::~FakeArcAppfuseProviderClient() = default;
+
+void FakeArcAppfuseProviderClient::Init(dbus::Bus* bus) {}
+
+void FakeArcAppfuseProviderClient::Mount(
+    uint32_t uid,
+    int32_t mount_id,
+    DBusMethodCallback<base::ScopedFD> callback) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), base::ScopedFD()));
+}
+
+void FakeArcAppfuseProviderClient::Unmount(uint32_t uid,
+                                           int32_t mount_id,
+                                           VoidDBusMethodCallback callback) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), false));
+}
+
+void FakeArcAppfuseProviderClient::OpenFile(
+    uint32_t uid,
+    int32_t mount_id,
+    int32_t file_id,
+    int32_t flags,
+    DBusMethodCallback<base::ScopedFD> callback) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), base::ScopedFD()));
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/fake_arc_appfuse_provider_client.h b/chromeos/dbus/fake_arc_appfuse_provider_client.h
new file mode 100644
index 0000000..cb8035d
--- /dev/null
+++ b/chromeos/dbus/fake_arc_appfuse_provider_client.h
@@ -0,0 +1,41 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_FAKE_ARC_APPFUSE_PROVIDER_CLIENT_H_
+#define CHROMEOS_DBUS_FAKE_ARC_APPFUSE_PROVIDER_CLIENT_H_
+
+#include "chromeos/dbus/arc_appfuse_provider_client.h"
+
+namespace chromeos {
+
+// A fake implementation of ArcAppfuseProviderClient.
+class CHROMEOS_EXPORT FakeArcAppfuseProviderClient
+    : public ArcAppfuseProviderClient {
+ public:
+  FakeArcAppfuseProviderClient();
+  ~FakeArcAppfuseProviderClient() override;
+
+  // DBusClient override.
+  void Init(dbus::Bus* bus) override;
+
+  // ArcAppfuseProviderClient override:
+  void Mount(uint32_t uid,
+             int32_t mount_id,
+             DBusMethodCallback<base::ScopedFD> callback) override;
+  void Unmount(uint32_t uid,
+               int32_t mount_id,
+               VoidDBusMethodCallback callback) override;
+  void OpenFile(uint32_t uid,
+                int32_t mount_id,
+                int32_t file_id,
+                int32_t flags,
+                DBusMethodCallback<base::ScopedFD> callback) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeArcAppfuseProviderClient);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_FAKE_ARC_APPFUSE_PROVIDER_CLIENT_H_
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index f70196f..37b769e 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -1536,7 +1536,6 @@
   return sync_prefs_.IsLocalSyncEnabled();
 }
 
-// TODO(tschumann): This is only called for tests. Add ForTesting name suffix.
 void ProfileSyncService::TriggerRefresh(const syncer::ModelTypeSet& types) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (engine_initialized_)
diff --git a/components/content_view/java/src/org/chromium/components/content_view/ContentView.java b/components/content_view/java/src/org/chromium/components/content_view/ContentView.java
index 210181c..65bd081 100644
--- a/components/content_view/java/src/org/chromium/components/content_view/ContentView.java
+++ b/components/content_view/java/src/org/chromium/components/content_view/ContentView.java
@@ -230,6 +230,7 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         ContentViewCore cvc = getContentViewCore();
         if (cvc != null) cvc.onConfigurationChanged(newConfig);
+        super.onConfigurationChanged(newConfig);
     }
 
     /**
@@ -340,11 +341,6 @@
         return super.onGenericMotionEvent(event);
     }
 
-    @Override
-    public void super_onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-    }
-
     ///////////////////////////////////////////////////////////////////////////////////////////////
     //                End Implementation of ContentViewCore.InternalAccessDelegate               //
     ///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/components/download/internal/common/download_file_impl.cc b/components/download/internal/common/download_file_impl.cc
index 05d8f7c5..eefdd2ce 100644
--- a/components/download/internal/common/download_file_impl.cc
+++ b/components/download/internal/common/download_file_impl.cc
@@ -229,7 +229,7 @@
     CancelRequest(offset);
     return;
   }
-  DCHECK(source_streams_.find(offset) == source_streams_.end());
+
   source_streams_[offset] =
       std::make_unique<SourceStream>(offset, length, std::move(stream));
   OnSourceStreamAdded(source_streams_[offset].get());
diff --git a/components/download/internal/common/download_file_unittest.cc b/components/download/internal/common/download_file_unittest.cc
index f0f2204..3fb6077 100644
--- a/components/download/internal/common/download_file_unittest.cc
+++ b/components/download/internal/common/download_file_unittest.cc
@@ -1042,8 +1042,8 @@
       .RetiresOnSaturation();
 
   download_file_->AddInputStream(
-      std::unique_ptr<MockInputStream>(additional_streams_[0]),
-      strlen(kTestData1), DownloadSaveInfo::kLengthFullContent);
+      std::unique_ptr<MockInputStream>(additional_streams_[0]), 0,
+      DownloadSaveInfo::kLengthFullContent);
 
   // The stream should get terminated and reset the callback.
   EXPECT_TRUE(sink_callback_.is_null());
diff --git a/components/download/internal/common/download_item_impl.cc b/components/download/internal/common/download_item_impl.cc
index cd9f9b1..1574628 100644
--- a/components/download/internal/common/download_item_impl.cc
+++ b/components/download/internal/common/download_item_impl.cc
@@ -1479,8 +1479,9 @@
   if (state_ == RESUMING_INTERNAL)
     UpdateValidatorsOnResumption(new_create_info);
 
-  // If the download is not parallel, clear the |received_slices_|.
-  if (!received_slices_.empty() && !job_->IsParallelizable()) {
+  // If the download is not parallel download during resumption, clear the
+  // |received_slices_|.
+  if (!job_->IsParallelizable() && !received_slices_.empty()) {
     destination_info_.received_bytes =
         GetMaxContiguousDataBlockSizeFromBeginning(received_slices_);
     received_slices_.clear();
diff --git a/components/download/internal/common/download_job_factory.cc b/components/download/internal/common/download_job_factory.cc
index c9cffbeb..4071ba6b 100644
--- a/components/download/internal/common/download_job_factory.cc
+++ b/components/download/internal/common/download_job_factory.cc
@@ -44,12 +44,10 @@
                                  net::HttpResponseInfo::CONNECTION_INFO_HTTP1_1;
   bool http_get_method =
       create_info.method == "GET" && create_info.url().SchemeIsHTTPOrHTTPS();
-  bool partial_response_success =
-      download_item->GetReceivedSlices().empty() || create_info.offset != 0;
+
   bool is_parallelizable = has_strong_validator && create_info.accept_range &&
                            has_content_length && satisfy_min_file_size &&
-                           satisfy_connection_type && http_get_method &&
-                           partial_response_success;
+                           satisfy_connection_type && http_get_method;
 
   if (!IsParallelDownloadEnabled())
     return is_parallelizable;
diff --git a/components/download/internal/common/download_worker.cc b/components/download/internal/common/download_worker.cc
index b6f3aa5..49cdc605 100644
--- a/components/download/internal/common/download_worker.cc
+++ b/components/download/internal/common/download_worker.cc
@@ -137,8 +137,7 @@
     Pause();
   }
 
-  delegate_->OnInputStreamReady(this, std::move(input_stream),
-                                std::move(create_info));
+  delegate_->OnInputStreamReady(this, std::move(input_stream));
 }
 
 void DownloadWorker::OnUrlDownloadStopped(UrlDownloadHandler* downloader) {
diff --git a/components/download/internal/common/download_worker.h b/components/download/internal/common/download_worker.h
index 8c71260..2c411a3e 100644
--- a/components/download/internal/common/download_worker.h
+++ b/components/download/internal/common/download_worker.h
@@ -31,8 +31,7 @@
     // destination file.
     virtual void OnInputStreamReady(
         DownloadWorker* worker,
-        std::unique_ptr<InputStream> input_stream,
-        std::unique_ptr<DownloadCreateInfo> download_create_info) = 0;
+        std::unique_ptr<InputStream> input_stream) = 0;
   };
 
   DownloadWorker(DownloadWorker::Delegate* delegate,
diff --git a/components/download/internal/common/parallel_download_job.cc b/components/download/internal/common/parallel_download_job.cc
index e72f9af..b0eae34 100644
--- a/components/download/internal/common/parallel_download_job.cc
+++ b/components/download/internal/common/parallel_download_job.cc
@@ -123,14 +123,9 @@
 
 void ParallelDownloadJob::OnInputStreamReady(
     DownloadWorker* worker,
-    std::unique_ptr<InputStream> input_stream,
-    std::unique_ptr<DownloadCreateInfo> download_create_info) {
-  // If server returns a wrong range, abort the parallel request.
-  bool success = download_create_info->offset == worker->offset();
-  if (success) {
-    success = DownloadJob::AddInputStream(std::move(input_stream),
-                                          worker->offset(), worker->length());
-  }
+    std::unique_ptr<InputStream> input_stream) {
+  bool success = DownloadJob::AddInputStream(
+      std::move(input_stream), worker->offset(), worker->length());
   RecordParallelDownloadAddStreamSuccess(success);
 
   // Destroy the request if the sink is gone.
diff --git a/components/download/internal/common/parallel_download_job.h b/components/download/internal/common/parallel_download_job.h
index a6803e2..2a1de8f 100644
--- a/components/download/internal/common/parallel_download_job.h
+++ b/components/download/internal/common/parallel_download_job.h
@@ -68,10 +68,8 @@
   friend class ParallelDownloadJobTest;
 
   // DownloadWorker::Delegate implementation.
-  void OnInputStreamReady(
-      DownloadWorker* worker,
-      std::unique_ptr<InputStream> input_stream,
-      std::unique_ptr<DownloadCreateInfo> download_create_info) override;
+  void OnInputStreamReady(DownloadWorker* worker,
+                          std::unique_ptr<InputStream> input_stream) override;
 
   // Build parallel requests after a delay, to effectively measure the single
   // stream bandwidth.
diff --git a/components/download/internal/common/parallel_download_job_unittest.cc b/components/download/internal/common/parallel_download_job_unittest.cc
index 61761c4..ff5e9bc 100644
--- a/components/download/internal/common/parallel_download_job_unittest.cc
+++ b/components/download/internal/common/parallel_download_job_unittest.cc
@@ -94,10 +94,8 @@
     return min_remaining_time_;
   }
 
-  void OnInputStreamReady(
-      DownloadWorker* worker,
-      std::unique_ptr<InputStream> input_stream,
-      std::unique_ptr<DownloadCreateInfo> download_create_info) override {
+  void OnInputStreamReady(DownloadWorker* worker,
+                          std::unique_ptr<InputStream> input_stream) override {
     CountOnInputStreamReady();
   }
 
diff --git a/components/drive/chromeos/about_resource_loader.cc b/components/drive/chromeos/about_resource_loader.cc
index 2eaf04d..050cd4e 100644
--- a/components/drive/chromeos/about_resource_loader.cc
+++ b/components/drive/chromeos/about_resource_loader.cc
@@ -4,6 +4,7 @@
 
 #include "components/drive/chromeos/about_resource_loader.h"
 
+#include <memory>
 #include <vector>
 
 #include "base/threading/thread_task_runner_handle.h"
@@ -17,7 +18,7 @@
       current_update_task_id_(-1),
       weak_ptr_factory_(this) {}
 
-AboutResourceLoader::~AboutResourceLoader() {}
+AboutResourceLoader::~AboutResourceLoader() = default;
 
 void AboutResourceLoader::GetAboutResource(
     const google_apis::AboutResourceCallback& callback) {
@@ -77,7 +78,8 @@
                  << "local = " << cached_about_resource_->largest_change_id()
                  << ", server = " << about_resource->largest_change_id();
   }
-  cached_about_resource_.reset(new google_apis::AboutResource(*about_resource));
+  cached_about_resource_ =
+      std::make_unique<google_apis::AboutResource>(*about_resource);
 
   for (auto& callback : callbacks) {
     callback.Run(status,
diff --git a/components/drive/chromeos/change_list_loader.cc b/components/drive/chromeos/change_list_loader.cc
index f75fb08..94a248d5 100644
--- a/components/drive/chromeos/change_list_loader.cc
+++ b/components/drive/chromeos/change_list_loader.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 
+#include <memory>
 #include <set>
 #include <utility>
 
@@ -38,7 +39,7 @@
 
 class ChangeListLoader::FeedFetcher {
  public:
-  virtual ~FeedFetcher() {}
+  virtual ~FeedFetcher() = default;
   virtual void Run(const FeedFetcherCallback& callback) = 0;
 };
 
@@ -50,11 +51,11 @@
   TeamDriveListFetcher(JobScheduler* scheduler)
       : scheduler_(scheduler), weak_ptr_factory_(this) {}
 
-  ~TeamDriveListFetcher() override {}
+  ~TeamDriveListFetcher() override = default;
 
   void Run(const FeedFetcherCallback& callback) override {
-    DCHECK(thread_checker_.CalledOnValidThread());
-    DCHECK(!callback.is_null());
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+    DCHECK(callback);
 
     scheduler_->GetAllTeamDriveList(
         base::Bind(&TeamDriveListFetcher::OnTeamDriveListFetched,
@@ -66,8 +67,8 @@
       const FeedFetcherCallback& callback,
       google_apis::DriveApiErrorCode status,
       std::unique_ptr<google_apis::TeamDriveList> team_drives) {
-    DCHECK(thread_checker_.CalledOnValidThread());
-    DCHECK(!callback.is_null());
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+    DCHECK(callback);
 
     FileError error = GDataToFileError(status);
     if (error != FILE_ERROR_OK) {
@@ -94,7 +95,7 @@
 
   JobScheduler* scheduler_;
   std::vector<std::unique_ptr<ChangeList>> change_lists_;
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
   base::WeakPtrFactory<TeamDriveListFetcher> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(TeamDriveListFetcher);
 };
@@ -105,11 +106,11 @@
   FullFeedFetcher(JobScheduler* scheduler)
       : scheduler_(scheduler), weak_ptr_factory_(this) {}
 
-  ~FullFeedFetcher() override {}
+  ~FullFeedFetcher() override = default;
 
   void Run(const FeedFetcherCallback& callback) override {
-    DCHECK(thread_checker_.CalledOnValidThread());
-    DCHECK(!callback.is_null());
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+    DCHECK(callback);
 
     // Remember the time stamp for usage stats.
     start_time_ = base::TimeTicks::Now();
@@ -126,8 +127,8 @@
   void OnFileListFetched(const FeedFetcherCallback& callback,
                          google_apis::DriveApiErrorCode status,
                          std::unique_ptr<google_apis::FileList> file_list) {
-    DCHECK(thread_checker_.CalledOnValidThread());
-    DCHECK(!callback.is_null());
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+    DCHECK(callback);
 
     FileError error = GDataToFileError(status);
     if (error != FILE_ERROR_OK) {
@@ -159,7 +160,7 @@
   JobScheduler* scheduler_;
   std::vector<std::unique_ptr<ChangeList>> change_lists_;
   base::TimeTicks start_time_;
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
   base::WeakPtrFactory<FullFeedFetcher> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(FullFeedFetcher);
 };
@@ -172,11 +173,11 @@
         start_change_id_(start_change_id),
         weak_ptr_factory_(this) {}
 
-  ~DeltaFeedFetcher() override {}
+  ~DeltaFeedFetcher() override = default;
 
   void Run(const FeedFetcherCallback& callback) override {
-    DCHECK(thread_checker_.CalledOnValidThread());
-    DCHECK(!callback.is_null());
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+    DCHECK(callback);
 
     scheduler_->GetChangeList(
         start_change_id_,
@@ -189,8 +190,8 @@
       const FeedFetcherCallback& callback,
       google_apis::DriveApiErrorCode status,
       std::unique_ptr<google_apis::ChangeList> change_list) {
-    DCHECK(thread_checker_.CalledOnValidThread());
-    DCHECK(!callback.is_null());
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+    DCHECK(callback);
 
     FileError error = GDataToFileError(status);
     if (error != FILE_ERROR_OK) {
@@ -219,7 +220,7 @@
   JobScheduler* scheduler_;
   int64_t start_change_id_;
   std::vector<std::unique_ptr<ChangeList>> change_lists_;
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
   base::WeakPtrFactory<DeltaFeedFetcher> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(DeltaFeedFetcher);
 };
@@ -259,18 +260,18 @@
 }
 
 void ChangeListLoader::AddObserver(ChangeListLoaderObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   observers_.AddObserver(observer);
 }
 
 void ChangeListLoader::RemoveObserver(ChangeListLoaderObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   observers_.RemoveObserver(observer);
 }
 
 void ChangeListLoader::CheckForUpdates(const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   // We only start to check for updates iff the load is done.
   // I.e., we ignore checking updates if not loaded to avoid starting the
@@ -296,8 +297,8 @@
 }
 
 void ChangeListLoader::LoadIfNeeded(const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   // If the metadata is not yet loaded, start loading.
   if (!loaded_ && !IsRefreshing())
@@ -305,8 +306,8 @@
 }
 
 void ChangeListLoader::Load(const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   // Check if this is the first time this ChangeListLoader do loading.
   // Note: IsRefreshing() depends on pending_load_callback_ so check in advance.
@@ -337,7 +338,7 @@
     bool is_initial_load,
     const int64_t* local_changestamp,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   if (error != FILE_ERROR_OK) {
     OnChangeListLoadComplete(error);
@@ -363,7 +364,7 @@
     int64_t local_changestamp,
     google_apis::DriveApiErrorCode status,
     std::unique_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!change_feed_fetcher_);
 
   FileError error = GDataToFileError(status);
@@ -378,7 +379,7 @@
   // directories of each Team Drive like /team_drive/My Team Drive/.
   if (google_apis::GetTeamDrivesIntegrationSwitch() ==
       google_apis::TEAM_DRIVES_INTEGRATION_ENABLED) {
-    change_feed_fetcher_.reset(new TeamDriveListFetcher(scheduler_));
+    change_feed_fetcher_ = std::make_unique<TeamDriveListFetcher>(scheduler_);
 
     change_feed_fetcher_->Run(
         base::Bind(&ChangeListLoader::LoadChangeListFromServer,
@@ -393,7 +394,7 @@
 }
 
 void ChangeListLoader::OnChangeListLoadComplete(FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   if (!loaded_ && error == FILE_ERROR_OK) {
     loaded_ = true;
@@ -410,7 +411,7 @@
 
   // If there is pending update check, try to load the change from the server
   // again, because there may exist an update during the completed loading.
-  if (!pending_update_check_callback_.is_null()) {
+  if (pending_update_check_callback_) {
     Load(base::ResetAndReturn(&pending_update_check_callback_));
   }
 }
@@ -418,7 +419,7 @@
 void ChangeListLoader::OnAboutResourceUpdated(
     google_apis::DriveApiErrorCode error,
     std::unique_ptr<google_apis::AboutResource> resource) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   if (drive::GDataToFileError(error) != drive::FILE_ERROR_OK) {
     logger_->Log(logging::LOG_ERROR,
@@ -436,7 +437,7 @@
     int64_t local_changestamp,
     FileError error,
     std::vector<std::unique_ptr<ChangeList>> team_drives_change_lists) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(about_resource);
 
   if (error != FILE_ERROR_OK) {
@@ -470,10 +471,10 @@
   // Set up feed fetcher.
   bool is_delta_update = start_changestamp != 0;
   if (is_delta_update) {
-    change_feed_fetcher_.reset(
-        new DeltaFeedFetcher(scheduler_, start_changestamp));
+    change_feed_fetcher_ =
+        std::make_unique<DeltaFeedFetcher>(scheduler_, start_changestamp);
   } else {
-    change_feed_fetcher_.reset(new FullFeedFetcher(scheduler_));
+    change_feed_fetcher_ = std::make_unique<FullFeedFetcher>(scheduler_);
   }
 
   // Make a copy of cached_about_resource_ to remember at which changestamp we
@@ -490,7 +491,7 @@
     std::vector<std::unique_ptr<ChangeList>> team_drives_change_lists,
     FileError error,
     std::vector<std::unique_ptr<ChangeList>> change_lists) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(about_resource);
 
   // Delete the fetcher first.
@@ -538,7 +539,7 @@
     bool should_notify_changed_directories,
     const base::Time& start_time,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   const base::TimeDelta elapsed = base::Time::Now() - start_time;
   logger_->Log(logging::LOG_INFO,
diff --git a/components/drive/chromeos/change_list_loader.h b/components/drive/chromeos/change_list_loader.h
index 511ef59..56f5a12 100644
--- a/components/drive/chromeos/change_list_loader.h
+++ b/components/drive/chromeos/change_list_loader.h
@@ -163,7 +163,7 @@
   // stored locally).
   bool loaded_;
 
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
diff --git a/components/drive/chromeos/change_list_loader_observer.h b/components/drive/chromeos/change_list_loader_observer.h
index d795f891..cd40569 100644
--- a/components/drive/chromeos/change_list_loader_observer.h
+++ b/components/drive/chromeos/change_list_loader_observer.h
@@ -35,7 +35,7 @@
   virtual void OnInitialLoadComplete() {}
 
  protected:
-  virtual ~ChangeListLoaderObserver() {}
+  virtual ~ChangeListLoaderObserver() = default;
 };
 
 }  // namespace internal
diff --git a/components/drive/chromeos/change_list_processor.cc b/components/drive/chromeos/change_list_processor.cc
index c99934f..f904f34 100644
--- a/components/drive/chromeos/change_list_processor.cc
+++ b/components/drive/chromeos/change_list_processor.cc
@@ -43,7 +43,7 @@
           ", changestamp: " + base::Int64ToString(changestamp_));
 }
 
-ChangeList::ChangeList() {}
+ChangeList::ChangeList() = default;
 
 ChangeList::ChangeList(const google_apis::TeamDriveList& team_drive_list) {
   const std::vector<std::unique_ptr<google_apis::TeamDriveResource>>& items =
@@ -94,7 +94,7 @@
   parent_resource_ids_.resize(entries_index);
 }
 
-ChangeList::~ChangeList() {}
+ChangeList::~ChangeList() = default;
 
 class ChangeListProcessor::ChangeListToEntryMapUMAStats {
  public:
@@ -127,8 +127,7 @@
       changed_files_(new FileChange) {
 }
 
-ChangeListProcessor::~ChangeListProcessor() {
-}
+ChangeListProcessor::~ChangeListProcessor() = default;
 
 FileError ChangeListProcessor::ApplyUserChangeList(
     std::unique_ptr<google_apis::AboutResource> about_resource,
diff --git a/components/drive/chromeos/directory_loader.cc b/components/drive/chromeos/directory_loader.cc
index fa1e1937..869d071 100644
--- a/components/drive/chromeos/directory_loader.cc
+++ b/components/drive/chromeos/directory_loader.cc
@@ -111,8 +111,8 @@
   ~FeedFetcher() = default;
 
   void Run(const FileOperationCallback& callback) {
-    DCHECK(thread_checker_.CalledOnValidThread());
-    DCHECK(!callback.is_null());
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+    DCHECK(callback);
     DCHECK(!directory_fetch_info_.resource_id().empty());
 
     // Remember the time stamp for usage stats.
@@ -128,8 +128,8 @@
   void OnFileListFetched(const FileOperationCallback& callback,
                          google_apis::DriveApiErrorCode status,
                          std::unique_ptr<google_apis::FileList> file_list) {
-    DCHECK(thread_checker_.CalledOnValidThread());
-    DCHECK(!callback.is_null());
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+    DCHECK(callback);
 
     FileError error = GDataToFileError(status);
     if (error != FILE_ERROR_OK) {
@@ -158,8 +158,8 @@
       const GURL& next_url,
       const std::vector<ResourceEntry>* refreshed_entries,
       FileError error) {
-    DCHECK(thread_checker_.CalledOnValidThread());
-    DCHECK(!callback.is_null());
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+    DCHECK(callback);
 
     if (error != FILE_ERROR_OK) {
       callback.Run(error);
@@ -190,7 +190,7 @@
   DirectoryFetchInfo directory_fetch_info_;
   std::string root_folder_id_;
   base::TimeTicks start_time_;
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
   base::WeakPtrFactory<FeedFetcher> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(FeedFetcher);
 };
@@ -214,12 +214,12 @@
 DirectoryLoader::~DirectoryLoader() = default;
 
 void DirectoryLoader::AddObserver(ChangeListLoaderObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   observers_.AddObserver(observer);
 }
 
 void DirectoryLoader::RemoveObserver(ChangeListLoaderObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   observers_.RemoveObserver(observer);
 }
 
@@ -227,8 +227,8 @@
     const base::FilePath& directory_path,
     const ReadDirectoryEntriesCallback& entries_callback,
     const FileOperationCallback& completion_callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!completion_callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(completion_callback);
 
   ResourceEntry* entry = new ResourceEntry;
   base::PostTaskAndReplyWithResult(
@@ -254,8 +254,8 @@
     bool should_try_loading_parent,
     const ResourceEntry* entry,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!completion_callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(completion_callback);
 
   if (error == FILE_ERROR_NOT_FOUND &&
       should_try_loading_parent &&
@@ -306,8 +306,8 @@
     const ReadDirectoryEntriesCallback& entries_callback,
     const FileOperationCallback& completion_callback,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!completion_callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(completion_callback);
 
   if (error != FILE_ERROR_OK) {
     completion_callback.Run(error);
@@ -335,7 +335,7 @@
     const std::string& local_id,
     google_apis::DriveApiErrorCode status,
     std::unique_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   FileError error = GDataToFileError(status);
   if (error != FILE_ERROR_OK) {
@@ -365,7 +365,7 @@
     const ResourceEntry* entry,
     const int64_t* local_changestamp,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(about_resource);
 
   if (error != FILE_ERROR_OK) {
@@ -403,7 +403,7 @@
 
 void DirectoryLoader::OnDirectoryLoadComplete(const std::string& local_id,
                                               FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   LoadCallbackMap::iterator it = pending_load_callback_.find(local_id);
   if (it == pending_load_callback_.end())
@@ -413,12 +413,12 @@
   bool needs_to_send_entries = false;
   for (size_t i = 0; i < it->second.size(); ++i) {
     const ReadDirectoryCallbackState& callback_state = it->second[i];
-    if (!callback_state.entries_callback.is_null())
+    if (callback_state.entries_callback)
       needs_to_send_entries = true;
   }
 
   if (!needs_to_send_entries) {
-    OnDirectoryLoadCompleteAfterRead(local_id, NULL, FILE_ERROR_OK);
+    OnDirectoryLoadCompleteAfterRead(local_id, nullptr, FILE_ERROR_OK);
     return;
   }
 
@@ -460,7 +460,7 @@
 
   for (size_t i = 0; i < it->second.size(); ++i) {
     ReadDirectoryCallbackState* callback_state = &it->second[i];
-    if (callback_state->entries_callback.is_null())
+    if (!callback_state->entries_callback)
       continue;
 
     // Filter out entries which were already sent.
@@ -479,7 +479,7 @@
 
 void DirectoryLoader::LoadDirectoryFromServer(
     const DirectoryFetchInfo& directory_fetch_info) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!directory_fetch_info.empty());
   DVLOG(1) << "Start loading directory: " << directory_fetch_info.ToString();
 
@@ -508,7 +508,7 @@
     const DirectoryFetchInfo& directory_fetch_info,
     FeedFetcher* fetcher,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!directory_fetch_info.empty());
 
   // Delete the fetcher.
@@ -552,7 +552,7 @@
     const DirectoryFetchInfo& directory_fetch_info,
     const base::FilePath* directory_path,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   DVLOG(1) << "Directory loaded: " << directory_fetch_info.ToString();
   OnDirectoryLoadComplete(directory_fetch_info.local_id(), error);
diff --git a/components/drive/chromeos/directory_loader.h b/components/drive/chromeos/directory_loader.h
index 483c2c2a..88eff34 100644
--- a/components/drive/chromeos/directory_loader.h
+++ b/components/drive/chromeos/directory_loader.h
@@ -138,7 +138,7 @@
   // Set of the running feed fetcher for the fast fetch.
   std::set<std::unique_ptr<FeedFetcher>> fast_fetch_feed_fetcher_set_;
 
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
diff --git a/components/drive/chromeos/dummy_file_system.h b/components/drive/chromeos/dummy_file_system.h
index e46935c..98b6d0ff 100644
--- a/components/drive/chromeos/dummy_file_system.h
+++ b/components/drive/chromeos/dummy_file_system.h
@@ -14,7 +14,7 @@
 // Dummy implementation of FileSystemInterface. All functions do nothing.
 class DummyFileSystem : public FileSystemInterface {
  public:
-  ~DummyFileSystem() override {}
+  ~DummyFileSystem() override = default;
   void AddObserver(FileSystemObserver* observer) override {}
   void RemoveObserver(FileSystemObserver* observer) override {}
   void CheckForUpdates() override {}
diff --git a/components/drive/chromeos/fake_file_system.cc b/components/drive/chromeos/fake_file_system.cc
index 9fae65f..1fd7a30e 100644
--- a/components/drive/chromeos/fake_file_system.cc
+++ b/components/drive/chromeos/fake_file_system.cc
@@ -35,8 +35,7 @@
   CHECK(cache_dir_.CreateUniqueTempDir());
 }
 
-FakeFileSystem::~FakeFileSystem() {
-}
+FakeFileSystem::~FakeFileSystem() = default;
 
 void FakeFileSystem::AddObserver(FileSystemObserver* observer) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/components/drive/chromeos/fake_free_disk_space_getter.cc b/components/drive/chromeos/fake_free_disk_space_getter.cc
index 3620c22..11ee033 100644
--- a/components/drive/chromeos/fake_free_disk_space_getter.cc
+++ b/components/drive/chromeos/fake_free_disk_space_getter.cc
@@ -12,8 +12,7 @@
     : default_value_(test_util::kLotsOfSpace) {
 }
 
-FakeFreeDiskSpaceGetter::~FakeFreeDiskSpaceGetter() {
-}
+FakeFreeDiskSpaceGetter::~FakeFreeDiskSpaceGetter() = default;
 
 void FakeFreeDiskSpaceGetter::PushFakeValue(int64_t value) {
   fake_values_.push_back(value);
diff --git a/components/drive/chromeos/file_cache.cc b/components/drive/chromeos/file_cache.cc
index 49b0fcce..e8aa3c5 100644
--- a/components/drive/chromeos/file_cache.cc
+++ b/components/drive/chromeos/file_cache.cc
@@ -8,6 +8,7 @@
 #include <sys/ioctl.h>
 #include <sys/xattr.h>
 
+#include <memory>
 #include <queue>
 #include <vector>
 
@@ -541,12 +542,10 @@
     return error;
 
   write_opened_files_[id]++;
-  file_closer->reset(new base::ScopedClosureRunner(
-      base::Bind(&google_apis::RunTaskWithTaskRunner,
-                 blocking_task_runner_,
+  *file_closer = std::make_unique<base::ScopedClosureRunner>(
+      base::Bind(&google_apis::RunTaskWithTaskRunner, blocking_task_runner_,
                  base::Bind(&FileCache::CloseForWrite,
-                            weak_ptr_factory_.GetWeakPtr(),
-                            id))));
+                            weak_ptr_factory_.GetWeakPtr(), id)));
   return FILE_ERROR_OK;
 }
 
@@ -688,7 +687,7 @@
 }
 
 void FileCache::Destroy() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   in_shutdown_.Set();
 
diff --git a/components/drive/chromeos/file_cache.h b/components/drive/chromeos/file_cache.h
index 8d58c30..8e3d1450 100644
--- a/components/drive/chromeos/file_cache.h
+++ b/components/drive/chromeos/file_cache.h
@@ -43,7 +43,7 @@
 // implementation that reports fake free disk space.
 class FreeDiskSpaceGetterInterface {
  public:
-  virtual ~FreeDiskSpaceGetterInterface() {}
+  virtual ~FreeDiskSpaceGetterInterface() = default;
   virtual int64_t AmountOfFreeDiskSpace() = 0;
 };
 
@@ -226,7 +226,7 @@
   // IDs of files marked mounted.
   std::set<std::string> mounted_files_;
 
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
diff --git a/components/drive/chromeos/file_cache_unittest.cc b/components/drive/chromeos/file_cache_unittest.cc
index 8e725f1..9472895 100644
--- a/components/drive/chromeos/file_cache_unittest.cc
+++ b/components/drive/chromeos/file_cache_unittest.cc
@@ -10,6 +10,7 @@
 #include <sys/ioctl.h>
 #include <sys/xattr.h>
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -77,7 +78,7 @@
     ASSERT_TRUE(base::CreateDirectory(metadata_dir));
     ASSERT_TRUE(base::CreateDirectory(cache_files_dir_));
 
-    fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
+    fake_free_disk_space_getter_ = std::make_unique<FakeFreeDiskSpaceGetter>();
 
     metadata_storage_.reset(new ResourceMetadataStorage(
         metadata_dir,
diff --git a/components/drive/chromeos/file_system.cc b/components/drive/chromeos/file_system.cc
index 1555ac5b..bbe98d6 100644
--- a/components/drive/chromeos/file_system.cc
+++ b/components/drive/chromeos/file_system.cc
@@ -5,6 +5,7 @@
 #include "components/drive/chromeos/file_system.h"
 
 #include <stddef.h>
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
@@ -93,7 +94,7 @@
 void RunGetResourceEntryCallback(const GetResourceEntryCallback& callback,
                                  std::unique_ptr<ResourceEntry> entry,
                                  FileError error) {
-  DCHECK(!callback.is_null());
+  DCHECK(callback);
 
   if (error != FILE_ERROR_OK)
     entry.reset();
@@ -166,7 +167,7 @@
 void RunMarkMountedCallback(const MarkMountedCallback& callback,
                             base::FilePath* cache_file_path,
                             FileError error) {
-  DCHECK(!callback.is_null());
+  DCHECK(callback);
   callback.Run(error, *cache_file_path);
 }
 
@@ -174,7 +175,7 @@
 void RunIsMountedCallback(const IsMountedCallback& callback,
                           bool* result,
                           FileError error) {
-  DCHECK(!callback.is_null());
+  DCHECK(callback);
   callback.Run(error, *result);
 }
 
@@ -184,7 +185,7 @@
                              const GetFilesystemMetadataCallback& callback,
                              const int64_t* largest_changestamp,
                              FileError error) {
-  DCHECK(!callback.is_null());
+  DCHECK(callback);
 
   metadata.largest_changestamp = *largest_changestamp;
   callback.Run(metadata);
@@ -248,7 +249,7 @@
 // Used to implement ReadDirectory().
 void FilterHostedDocuments(const ReadDirectoryEntriesCallback& callback,
                            std::unique_ptr<ResourceEntryVector> entries) {
-  DCHECK(!callback.is_null());
+  DCHECK(callback);
 
   if (entries) {
     // TODO(kinaba): Stop handling hide_hosted_docs here. crbug.com/256520.
@@ -326,7 +327,7 @@
 }
 
 FileSystem::~FileSystem() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   directory_loader_->RemoveObserver(this);
   change_list_loader_->RemoveObserver(this);
@@ -350,90 +351,59 @@
 void FileSystem::ResetComponents() {
   file_system::OperationDelegate* delegate = this;
 
-  about_resource_loader_.reset(new internal::AboutResourceLoader(scheduler_));
-  loader_controller_.reset(new internal::LoaderController);
-  change_list_loader_.reset(new internal::ChangeListLoader(
-      logger_,
-      blocking_task_runner_.get(),
-      resource_metadata_,
-      scheduler_,
-      about_resource_loader_.get(),
-      loader_controller_.get()));
+  about_resource_loader_ =
+      std::make_unique<internal::AboutResourceLoader>(scheduler_);
+  loader_controller_ = std::make_unique<internal::LoaderController>();
+  change_list_loader_ = std::make_unique<internal::ChangeListLoader>(
+      logger_, blocking_task_runner_.get(), resource_metadata_, scheduler_,
+      about_resource_loader_.get(), loader_controller_.get());
   change_list_loader_->AddObserver(this);
-  directory_loader_.reset(new internal::DirectoryLoader(
-      logger_,
-      blocking_task_runner_.get(),
-      resource_metadata_,
-      scheduler_,
-      about_resource_loader_.get(),
-      loader_controller_.get()));
+  directory_loader_ = std::make_unique<internal::DirectoryLoader>(
+      logger_, blocking_task_runner_.get(), resource_metadata_, scheduler_,
+      about_resource_loader_.get(), loader_controller_.get());
   directory_loader_->AddObserver(this);
 
-  sync_client_.reset(new internal::SyncClient(blocking_task_runner_.get(),
-                                              delegate,
-                                              scheduler_,
-                                              resource_metadata_,
-                                              cache_,
-                                              loader_controller_.get(),
-                                              temporary_file_directory_));
+  sync_client_ = std::make_unique<internal::SyncClient>(
+      blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_,
+      cache_, loader_controller_.get(), temporary_file_directory_);
 
-  copy_operation_.reset(
-      new file_system::CopyOperation(blocking_task_runner_.get(),
-                                     delegate,
-                                     scheduler_,
-                                     resource_metadata_,
-                                     cache_));
-  create_directory_operation_.reset(new file_system::CreateDirectoryOperation(
-      blocking_task_runner_.get(), delegate, resource_metadata_));
-  create_file_operation_.reset(
-      new file_system::CreateFileOperation(blocking_task_runner_.get(),
-                                           delegate,
-                                           resource_metadata_));
-  move_operation_.reset(
-      new file_system::MoveOperation(blocking_task_runner_.get(),
-                                     delegate,
-                                     resource_metadata_));
-  open_file_operation_.reset(
-      new file_system::OpenFileOperation(blocking_task_runner_.get(),
-                                         delegate,
-                                         scheduler_,
-                                         resource_metadata_,
-                                         cache_,
-                                         temporary_file_directory_));
-  remove_operation_.reset(
-      new file_system::RemoveOperation(blocking_task_runner_.get(),
-                                       delegate,
-                                       resource_metadata_,
-                                       cache_));
-  touch_operation_.reset(new file_system::TouchOperation(
-      blocking_task_runner_.get(), delegate, resource_metadata_));
-  truncate_operation_.reset(
-      new file_system::TruncateOperation(blocking_task_runner_.get(),
-                                         delegate,
-                                         scheduler_,
-                                         resource_metadata_,
-                                         cache_,
-                                         temporary_file_directory_));
-  download_operation_.reset(
-      new file_system::DownloadOperation(blocking_task_runner_.get(),
-                                         delegate,
-                                         scheduler_,
-                                         resource_metadata_,
-                                         cache_,
-                                         temporary_file_directory_));
-  search_operation_.reset(new file_system::SearchOperation(
+  copy_operation_ = std::make_unique<file_system::CopyOperation>(
+      blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_,
+      cache_);
+  create_directory_operation_ =
+      std::make_unique<file_system::CreateDirectoryOperation>(
+          blocking_task_runner_.get(), delegate, resource_metadata_);
+  create_file_operation_ = std::make_unique<file_system::CreateFileOperation>(
+      blocking_task_runner_.get(), delegate, resource_metadata_);
+  move_operation_ = std::make_unique<file_system::MoveOperation>(
+      blocking_task_runner_.get(), delegate, resource_metadata_);
+  open_file_operation_ = std::make_unique<file_system::OpenFileOperation>(
+      blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_,
+      cache_, temporary_file_directory_);
+  remove_operation_ = std::make_unique<file_system::RemoveOperation>(
+      blocking_task_runner_.get(), delegate, resource_metadata_, cache_);
+  touch_operation_ = std::make_unique<file_system::TouchOperation>(
+      blocking_task_runner_.get(), delegate, resource_metadata_);
+  truncate_operation_ = std::make_unique<file_system::TruncateOperation>(
+      blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_,
+      cache_, temporary_file_directory_);
+  download_operation_ = std::make_unique<file_system::DownloadOperation>(
+      blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_,
+      cache_, temporary_file_directory_);
+  search_operation_ = std::make_unique<file_system::SearchOperation>(
       blocking_task_runner_.get(), scheduler_, resource_metadata_,
-      loader_controller_.get()));
-  get_file_for_saving_operation_.reset(
-      new file_system::GetFileForSavingOperation(
+      loader_controller_.get());
+  get_file_for_saving_operation_ =
+      std::make_unique<file_system::GetFileForSavingOperation>(
+
           logger_, blocking_task_runner_.get(), delegate, scheduler_,
-          resource_metadata_, cache_, temporary_file_directory_));
-  set_property_operation_.reset(new file_system::SetPropertyOperation(
-      blocking_task_runner_.get(), delegate, resource_metadata_));
+          resource_metadata_, cache_, temporary_file_directory_);
+  set_property_operation_ = std::make_unique<file_system::SetPropertyOperation>(
+      blocking_task_runner_.get(), delegate, resource_metadata_);
 }
 
 void FileSystem::CheckForUpdates() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DVLOG(1) << "CheckForUpdates";
 
   change_list_loader_->CheckForUpdates(
@@ -441,19 +411,19 @@
 }
 
 void FileSystem::OnUpdateChecked(FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DVLOG(1) << "CheckForUpdates finished: " << FileErrorToString(error);
   last_update_check_time_ = base::Time::Now();
   last_update_check_error_ = error;
 }
 
 void FileSystem::AddObserver(FileSystemObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   observers_.AddObserver(observer);
 }
 
 void FileSystem::RemoveObserver(FileSystemObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   observers_.RemoveObserver(observer);
 }
 
@@ -461,8 +431,8 @@
     const base::FilePath& local_src_file_path,
     const base::FilePath& remote_dest_file_path,
     const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
   copy_operation_->TransferFileFromLocalToRemote(local_src_file_path,
                                                  remote_dest_file_path,
                                                  callback);
@@ -472,8 +442,8 @@
                       const base::FilePath& dest_file_path,
                       bool preserve_last_modified,
                       const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
   copy_operation_->Copy(
       src_file_path, dest_file_path, preserve_last_modified, callback);
 }
@@ -481,16 +451,16 @@
 void FileSystem::Move(const base::FilePath& src_file_path,
                       const base::FilePath& dest_file_path,
                       const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
   move_operation_->Move(src_file_path, dest_file_path, callback);
 }
 
 void FileSystem::Remove(const base::FilePath& file_path,
                         bool is_recursive,
                         const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
   remove_operation_->Remove(file_path, is_recursive, callback);
 }
 
@@ -499,8 +469,8 @@
     bool is_exclusive,
     bool is_recursive,
     const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   CreateDirectoryParams params;
   params.directory_path = directory_path;
@@ -517,8 +487,8 @@
 
 void FileSystem::CreateDirectoryAfterRead(const CreateDirectoryParams& params,
                                           FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!params.callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(params.callback);
 
   DVLOG_IF(1, error != FILE_ERROR_OK) << "ReadDirectory failed. "
                                       << FileErrorToString(error);
@@ -532,8 +502,8 @@
                             bool is_exclusive,
                             const std::string& mime_type,
                             const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
   create_file_operation_->CreateFile(
       file_path, is_exclusive, mime_type, callback);
 }
@@ -542,8 +512,8 @@
                            const base::Time& last_access_time,
                            const base::Time& last_modified_time,
                            const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
   touch_operation_->TouchFile(
       file_path, last_access_time, last_modified_time, callback);
 }
@@ -551,15 +521,15 @@
 void FileSystem::TruncateFile(const base::FilePath& file_path,
                               int64_t length,
                               const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
   truncate_operation_->Truncate(file_path, length, callback);
 }
 
 void FileSystem::Pin(const base::FilePath& file_path,
                      const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   std::string* local_id = new std::string;
   base::PostTaskAndReplyWithResult(
@@ -575,8 +545,8 @@
 void FileSystem::FinishPin(const FileOperationCallback& callback,
                            const std::string* local_id,
                            FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   if (error == FILE_ERROR_OK)
     sync_client_->AddFetchTask(*local_id);
@@ -585,8 +555,8 @@
 
 void FileSystem::Unpin(const base::FilePath& file_path,
                        const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   std::string* local_id = new std::string;
   base::PostTaskAndReplyWithResult(
@@ -603,8 +573,8 @@
 void FileSystem::FinishUnpin(const FileOperationCallback& callback,
                              const std::string* local_id,
                              FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   if (error == FILE_ERROR_OK)
     sync_client_->RemoveFetchTask(*local_id);
@@ -613,8 +583,8 @@
 
 void FileSystem::GetFile(const base::FilePath& file_path,
                          const GetFileCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   download_operation_->EnsureFileDownloadedByPath(
       file_path,
@@ -626,8 +596,8 @@
 
 void FileSystem::GetFileForSaving(const base::FilePath& file_path,
                                   const GetFileCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   get_file_for_saving_operation_->GetFileForSaving(file_path, callback);
 }
@@ -637,10 +607,10 @@
     const GetFileContentInitializedCallback& initialized_callback,
     const google_apis::GetContentCallback& get_content_callback,
     const FileOperationCallback& completion_callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!initialized_callback.is_null());
-  DCHECK(!get_content_callback.is_null());
-  DCHECK(!completion_callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(initialized_callback);
+  DCHECK(get_content_callback);
+  DCHECK(completion_callback);
 
   return download_operation_->EnsureFileDownloadedByPath(
       file_path,
@@ -654,8 +624,8 @@
 void FileSystem::GetResourceEntry(
     const base::FilePath& file_path,
     const GetResourceEntryCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   ReadDirectory(file_path.DirName(),
                 ReadDirectoryEntriesCallback(),
@@ -669,8 +639,8 @@
     const base::FilePath& file_path,
     const GetResourceEntryCallback& callback,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   DVLOG_IF(1, error != FILE_ERROR_OK) << "ReadDirectory failed. "
                                       << FileErrorToString(error);
@@ -688,13 +658,13 @@
     const base::FilePath& directory_path,
     const ReadDirectoryEntriesCallback& entries_callback_in,
     const FileOperationCallback& completion_callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!completion_callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(completion_callback);
 
   const bool hide_hosted_docs =
       pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles);
   ReadDirectoryEntriesCallback entries_callback = entries_callback_in;
-  if (!entries_callback.is_null() && hide_hosted_docs)
+  if (entries_callback && hide_hosted_docs)
     entries_callback = base::Bind(&FilterHostedDocuments, entries_callback);
 
   directory_loader_->ReadDirectory(
@@ -706,8 +676,8 @@
 
 void FileSystem::GetAvailableSpace(
     const GetAvailableSpaceCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   about_resource_loader_->GetAboutResource(
       base::Bind(&FileSystem::OnGetAboutResource,
@@ -719,8 +689,8 @@
     const GetAvailableSpaceCallback& callback,
     google_apis::DriveApiErrorCode status,
     std::unique_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   FileError error = GDataToFileError(status);
   if (error != FILE_ERROR_OK) {
@@ -736,8 +706,8 @@
 void FileSystem::GetShareUrl(const base::FilePath& file_path,
                              const GURL& embed_origin,
                              const GetShareUrlCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   // Resolve the resource id.
   ResourceEntry* entry = new ResourceEntry;
@@ -762,8 +732,8 @@
     const GetShareUrlCallback& callback,
     ResourceEntry* entry,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   if (error != FILE_ERROR_OK) {
     callback.Run(error, GURL());
@@ -788,8 +758,8 @@
     const GetShareUrlCallback& callback,
     google_apis::DriveApiErrorCode status,
     const GURL& share_url) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   FileError error = GDataToFileError(status);
   if (error != FILE_ERROR_OK) {
@@ -808,8 +778,8 @@
 void FileSystem::Search(const std::string& search_query,
                         const GURL& next_link,
                         const SearchCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
   search_operation_->Search(search_query, next_link, callback);
 }
 
@@ -818,7 +788,7 @@
                                 int at_most_num_matches,
                                 MetadataSearchOrder order,
                                 const SearchMetadataCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   // TODO(satorux): Stop handling hide_hosted_docs here. crbug.com/256520.
   if (pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles))
@@ -832,7 +802,7 @@
 
 void FileSystem::SearchByHashes(const std::set<std::string>& hashes,
                                 const SearchByHashesCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   drive::internal::SearchMetadata(
       blocking_task_runner_, resource_metadata_,
       /* any file name */ "", base::Bind(&CheckHashes, hashes),
@@ -842,7 +812,7 @@
 }
 
 void FileSystem::OnFileChangedByOperation(const FileChange& changed_files) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   for (auto& observer : observers_)
     observer.OnFileChanged(changed_files);
@@ -885,27 +855,27 @@
 }
 
 void FileSystem::OnDirectoryReloaded(const base::FilePath& directory_path) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   for (auto& observer : observers_)
     observer.OnDirectoryChanged(directory_path);
 }
 
 void FileSystem::OnFileChanged(const FileChange& changed_files) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   for (auto& observer : observers_)
     observer.OnFileChanged(changed_files);
 }
 
 void FileSystem::OnLoadFromServerComplete() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   sync_client_->StartCheckingExistingPinnedFiles();
 }
 
 void FileSystem::OnInitialLoadComplete() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   blocking_task_runner_->PostTask(FROM_HERE,
                                   base::Bind(&internal::RemoveStaleCacheFiles,
@@ -916,8 +886,8 @@
 
 void FileSystem::GetMetadata(
     const GetFilesystemMetadataCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   FileSystemMetadata metadata;
   metadata.refreshing = change_list_loader_->IsRefreshing();
@@ -942,8 +912,8 @@
 void FileSystem::MarkCacheFileAsMounted(
     const base::FilePath& drive_file_path,
     const MarkMountedCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   base::FilePath* cache_file_path = new base::FilePath;
   base::PostTaskAndReplyWithResult(
@@ -961,8 +931,8 @@
 void FileSystem::IsCacheFileMarkedAsMounted(
     const base::FilePath& drive_file_path,
     const IsMountedCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   bool* is_mounted = new bool(false);
   base::PostTaskAndReplyWithResult(
@@ -975,8 +945,8 @@
 void FileSystem::MarkCacheFileAsUnmounted(
     const base::FilePath& cache_file_path,
     const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   if (!cache_->IsUnderFileCacheDirectory(cache_file_path)) {
     callback.Run(FILE_ERROR_FAILED);
@@ -996,8 +966,8 @@
                                const std::string& email,
                                google_apis::drive::PermissionRole role,
                                const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   // Resolve the resource id.
   ResourceEntry* const entry = new ResourceEntry;
@@ -1022,7 +992,7 @@
     const FileOperationCallback& callback,
     ResourceEntry* entry,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   if (error != FILE_ERROR_OK) {
     callback.Run(error);
@@ -1042,8 +1012,8 @@
     const std::string& key,
     const std::string& value,
     const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   set_property_operation_->SetProperty(drive_file_path, visibility, key, value,
                                        callback);
@@ -1053,16 +1023,16 @@
                           OpenMode open_mode,
                           const std::string& mime_type,
                           const OpenFileCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   open_file_operation_->OpenFile(file_path, open_mode, mime_type, callback);
 }
 
 void FileSystem::GetPathFromResourceId(const std::string& resource_id,
                                        const GetFilePathCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   base::FilePath* const file_path = new base::FilePath();
   base::PostTaskAndReplyWithResult(
@@ -1080,8 +1050,8 @@
 void FileSystem::FreeDiskSpaceIfNeededFor(
     int64_t num_bytes,
     const FreeDiskSpaceCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(), FROM_HERE,
       base::Bind(&FreeDiskSpaceIfNeededForOnBlockingPool, cache_, num_bytes),
@@ -1089,8 +1059,8 @@
 }
 
 void FileSystem::CalculateCacheSize(const CacheSizeCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(), FROM_HERE,
       base::Bind(&CalculateCacheSizeOnBlockingPool, cache_), callback);
@@ -1098,8 +1068,8 @@
 
 void FileSystem::CalculateEvictableCacheSize(
     const CacheSizeCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(), FROM_HERE,
       base::Bind(&CalculateEvictableCacheSizeOnBlockingPool, cache_), callback);
diff --git a/components/drive/chromeos/file_system.h b/components/drive/chromeos/file_system.h
index a575f300..dc085e8 100644
--- a/components/drive/chromeos/file_system.h
+++ b/components/drive/chromeos/file_system.h
@@ -302,7 +302,7 @@
       get_file_for_saving_operation_;
   std::unique_ptr<file_system::SetPropertyOperation> set_property_operation_;
 
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
diff --git a/components/drive/chromeos/file_system_interface.h b/components/drive/chromeos/file_system_interface.h
index 9332d32..66bb335 100644
--- a/components/drive/chromeos/file_system_interface.h
+++ b/components/drive/chromeos/file_system_interface.h
@@ -194,7 +194,7 @@
 // The interface is defined to make FileSystem mockable.
 class FileSystemInterface {
  public:
-  virtual ~FileSystemInterface() {}
+  virtual ~FileSystemInterface() = default;
 
   // Adds and removes the observer.
   virtual void AddObserver(FileSystemObserver* observer) = 0;
diff --git a/components/drive/chromeos/file_system_observer.h b/components/drive/chromeos/file_system_observer.h
index 7b9379f..714943c3 100644
--- a/components/drive/chromeos/file_system_observer.h
+++ b/components/drive/chromeos/file_system_observer.h
@@ -33,7 +33,7 @@
                                 const base::FilePath& file_path) {}
 
  protected:
-  virtual ~FileSystemObserver() {}
+  virtual ~FileSystemObserver() = default;
 };
 
 }  // namespace drive
diff --git a/components/drive/chromeos/resource_metadata.cc b/components/drive/chromeos/resource_metadata.cc
index e73edf2..6ad3883 100644
--- a/components/drive/chromeos/resource_metadata.cc
+++ b/components/drive/chromeos/resource_metadata.cc
@@ -85,7 +85,7 @@
 }
 
 void ResourceMetadata::Destroy() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   blocking_task_runner_->PostTask(
       FROM_HERE,
diff --git a/components/drive/chromeos/resource_metadata.h b/components/drive/chromeos/resource_metadata.h
index 03bc001..ba208c8 100644
--- a/components/drive/chromeos/resource_metadata.h
+++ b/components/drive/chromeos/resource_metadata.h
@@ -146,7 +146,7 @@
   ResourceMetadataStorage* storage_;
   FileCache* cache_;
 
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(ResourceMetadata);
 };
diff --git a/components/drive/chromeos/search_metadata.cc b/components/drive/chromeos/search_metadata.cc
index fe24ed7..5c80e66 100644
--- a/components/drive/chromeos/search_metadata.cc
+++ b/components/drive/chromeos/search_metadata.cc
@@ -283,7 +283,7 @@
     size_t at_most_num_matches,
     MetadataSearchOrder order,
     const SearchMetadataCallback& callback) {
-  DCHECK(!callback.is_null());
+  DCHECK(callback);
 
   const base::TimeTicks start_time = base::TimeTicks::Now();
 
diff --git a/components/drive/chromeos/sync/entry_revert_performer.cc b/components/drive/chromeos/sync/entry_revert_performer.cc
index 38b4dfe20..cdf22ba2 100644
--- a/components/drive/chromeos/sync/entry_revert_performer.cc
+++ b/components/drive/chromeos/sync/entry_revert_performer.cc
@@ -96,14 +96,14 @@
 }
 
 EntryRevertPerformer::~EntryRevertPerformer() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 }
 
 void EntryRevertPerformer::RevertEntry(const std::string& local_id,
                                        const ClientContext& context,
                                        const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   std::unique_ptr<ResourceEntry> entry(new ResourceEntry);
   ResourceEntry* entry_ptr = entry.get();
@@ -121,8 +121,8 @@
     const FileOperationCallback& callback,
     std::unique_ptr<ResourceEntry> entry,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   if (error == FILE_ERROR_OK && entry->resource_id().empty())
     error = FILE_ERROR_INVALID_OPERATION;
@@ -144,8 +144,8 @@
     const std::string& local_id,
     google_apis::DriveApiErrorCode status,
     std::unique_ptr<google_apis::FileResource> entry) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   FileChange* changed_files = new FileChange;
   base::PostTaskAndReplyWithResult(
@@ -161,8 +161,8 @@
     const FileOperationCallback& callback,
     const FileChange* changed_files,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   delegate_->OnFileChangedByOperation(*changed_files);
 
diff --git a/components/drive/chromeos/sync/entry_revert_performer.h b/components/drive/chromeos/sync/entry_revert_performer.h
index 6b9d9c32..23e6f12f 100644
--- a/components/drive/chromeos/sync/entry_revert_performer.h
+++ b/components/drive/chromeos/sync/entry_revert_performer.h
@@ -79,7 +79,7 @@
   JobScheduler* scheduler_;
   ResourceMetadata* metadata_;
 
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
diff --git a/components/drive/chromeos/sync/entry_update_performer.cc b/components/drive/chromeos/sync/entry_update_performer.cc
index 1276e11..f681f1d 100644
--- a/components/drive/chromeos/sync/entry_update_performer.cc
+++ b/components/drive/chromeos/sync/entry_update_performer.cc
@@ -248,14 +248,14 @@
 }
 
 EntryUpdatePerformer::~EntryUpdatePerformer() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 }
 
 void EntryUpdatePerformer::UpdateEntry(const std::string& local_id,
                                        const ClientContext& context,
                                        const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   std::unique_ptr<LocalState> local_state(new LocalState);
   LocalState* const local_state_ptr = local_state.get();
@@ -273,8 +273,8 @@
     const FileOperationCallback& callback,
     std::unique_ptr<LocalState> local_state,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   if (error != FILE_ERROR_OK) {
     callback.Run(error);
@@ -413,8 +413,8 @@
     std::unique_ptr<base::ScopedClosureRunner> loader_lock,
     google_apis::DriveApiErrorCode status,
     std::unique_ptr<google_apis::FileResource> entry) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   if (status == google_apis::HTTP_FORBIDDEN) {
     // Editing this entry is not allowed, revert local changes.
@@ -443,8 +443,8 @@
     const FileOperationCallback& callback,
     const FileChange* changed_files,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   delegate_->OnFileChangedByOperation(*changed_files);
   callback.Run(error);
diff --git a/components/drive/chromeos/sync/entry_update_performer.h b/components/drive/chromeos/sync/entry_update_performer.h
index 1cc4c9c1..9c1c17a 100644
--- a/components/drive/chromeos/sync/entry_update_performer.h
+++ b/components/drive/chromeos/sync/entry_update_performer.h
@@ -92,7 +92,7 @@
   std::unique_ptr<RemovePerformer> remove_performer_;
   std::unique_ptr<EntryRevertPerformer> entry_revert_performer_;
 
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
diff --git a/components/drive/chromeos/sync/remove_performer.cc b/components/drive/chromeos/sync/remove_performer.cc
index fa59c4ab..9291181 100644
--- a/components/drive/chromeos/sync/remove_performer.cc
+++ b/components/drive/chromeos/sync/remove_performer.cc
@@ -63,7 +63,7 @@
 }
 
 RemovePerformer::~RemovePerformer() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 }
 
 // Returns |entry| corresponding to |local_id|.
@@ -80,8 +80,8 @@
 void RemovePerformer::Remove(const std::string& local_id,
                              const ClientContext& context,
                              const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   ResourceEntry* entry = new ResourceEntry;
   base::PostTaskAndReplyWithResult(
@@ -100,8 +100,8 @@
     const FileOperationCallback& callback,
     const ResourceEntry* entry,
     FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   if (error != FILE_ERROR_OK || entry->resource_id().empty()) {
     callback.Run(error);
@@ -128,8 +128,8 @@
                                     const FileOperationCallback& callback,
                                     const std::string& resource_id,
                                     const std::string& local_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   scheduler_->TrashResource(
       resource_id,
@@ -143,8 +143,8 @@
     const FileOperationCallback& callback,
     const std::string& local_id,
     google_apis::DriveApiErrorCode status) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   if (status == google_apis::HTTP_FORBIDDEN) {
     // Editing this entry is not allowed, revert local changes.
@@ -170,8 +170,8 @@
                                        const FileOperationCallback& callback,
                                        const std::string& resource_id,
                                        const std::string& local_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   scheduler_->GetFileResource(
       resource_id,
@@ -186,8 +186,8 @@
     const std::string& local_id,
     google_apis::DriveApiErrorCode status,
     std::unique_ptr<google_apis::FileResource> file_resource) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   FileError error = GDataToFileError(status);
   if (error == FILE_ERROR_NOT_FOUND) {  // Remove local entry when not found.
@@ -235,8 +235,8 @@
     const FileOperationCallback& callback,
     const std::string& local_id,
     google_apis::DriveApiErrorCode status) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!callback.is_null());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(callback);
 
   FileError error = GDataToFileError(status);
   if (error != FILE_ERROR_OK) {
diff --git a/components/drive/chromeos/sync/remove_performer.h b/components/drive/chromeos/sync/remove_performer.h
index 4e1bf91..e085b1c 100644
--- a/components/drive/chromeos/sync/remove_performer.h
+++ b/components/drive/chromeos/sync/remove_performer.h
@@ -101,7 +101,7 @@
   ResourceMetadata* metadata_;
   std::unique_ptr<EntryRevertPerformer> entry_revert_performer_;
 
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
diff --git a/components/drive/chromeos/sync_client.cc b/components/drive/chromeos/sync_client.cc
index c855017..235495c 100644
--- a/components/drive/chromeos/sync_client.cc
+++ b/components/drive/chromeos/sync_client.cc
@@ -136,7 +136,7 @@
 SyncClient::SyncTask::SyncTask()
     : state(SUSPENDED), context(BACKGROUND), should_run_again(false) {}
 SyncClient::SyncTask::SyncTask(const SyncTask& other) = default;
-SyncClient::SyncTask::~SyncTask() {}
+SyncClient::SyncTask::~SyncTask() = default;
 
 SyncClient::SyncClient(base::SequencedTaskRunner* blocking_task_runner,
                        file_system::OperationDelegate* delegate,
@@ -168,11 +168,11 @@
 }
 
 SyncClient::~SyncClient() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 }
 
 void SyncClient::StartProcessingBacklog() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   std::vector<std::string>* to_fetch = new std::vector<std::string>;
   std::vector<std::string>* to_update = new std::vector<std::string>;
@@ -186,7 +186,7 @@
 }
 
 void SyncClient::StartCheckingExistingPinnedFiles() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   std::vector<std::string>* local_ids = new std::vector<std::string>;
   blocking_task_runner_->PostTaskAndReply(
@@ -201,12 +201,12 @@
 }
 
 void SyncClient::AddFetchTask(const std::string& local_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   AddFetchTaskInternal(local_id, delay_);
 }
 
 void SyncClient::RemoveFetchTask(const std::string& local_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   SyncTasks::iterator it = tasks_.find(SyncTasks::key_type(FETCH, local_id));
   if (it == tasks_.end())
@@ -219,7 +219,7 @@
       OnTaskComplete(FETCH, local_id, FILE_ERROR_ABORT);
       break;
     case RUNNING:
-      if (!task->cancel_closure.is_null())
+      if (task->cancel_closure)
         task->cancel_closure.Run();
       break;
   }
@@ -227,14 +227,14 @@
 
 void SyncClient::AddUpdateTask(const ClientContext& context,
                                const std::string& local_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   AddUpdateTaskInternal(context, local_id, delay_);
 }
 
 bool SyncClient:: WaitForUpdateTaskToComplete(
     const std::string& local_id,
     const FileOperationCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   SyncTasks::iterator it = tasks_.find(SyncTasks::key_type(UPDATE, local_id));
   if (it == tasks_.end())
@@ -247,7 +247,7 @@
 
 base::Closure SyncClient::PerformFetchTask(const std::string& local_id,
                                            const ClientContext& context) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   return download_operation_->EnsureFileDownloadedByLocalId(
       local_id,
       context,
@@ -260,7 +260,7 @@
 
 void SyncClient::AddFetchTaskInternal(const std::string& local_id,
                                       const base::TimeDelta& delay) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   SyncTask task;
   task.state = PENDING;
@@ -273,7 +273,7 @@
 
 base::Closure SyncClient::PerformUpdateTask(const std::string& local_id,
                                             const ClientContext& context) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   entry_update_performer_->UpdateEntry(
       local_id,
       context,
@@ -287,7 +287,7 @@
 void SyncClient::AddUpdateTaskInternal(const ClientContext& context,
                                        const std::string& local_id,
                                        const base::TimeDelta& delay) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   SyncTask task;
   task.state = PENDING;
@@ -301,7 +301,7 @@
 void SyncClient::AddTask(const SyncTasks::key_type& key,
                          const SyncTask& task,
                          const base::TimeDelta& delay) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   SyncTasks::iterator it = tasks_.find(key);
   if (it != tasks_.end()) {
@@ -390,7 +390,7 @@
 void SyncClient::OnGetLocalIdsOfBacklog(
     const std::vector<std::string>* to_fetch,
     const std::vector<std::string>* to_update) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   // Give priority to upload tasks over fetch tasks, so that dirty files are
   // uploaded as soon as possible.
@@ -408,7 +408,7 @@
 }
 
 void SyncClient::AddFetchTasks(const std::vector<std::string>* local_ids) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   for (size_t i = 0; i < local_ids->size(); ++i)
     AddFetchTask((*local_ids)[i]);
@@ -417,7 +417,7 @@
 void SyncClient::OnTaskComplete(SyncType type,
                                 const std::string& local_id,
                                 FileError error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   const SyncTasks::key_type key(type, local_id);
   SyncTasks::iterator it = tasks_.find(key);
@@ -481,7 +481,7 @@
                                      FileError error,
                                      const base::FilePath& local_path,
                                      std::unique_ptr<ResourceEntry> entry) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   OnTaskComplete(FETCH, local_id, error);
   if (error == FILE_ERROR_ABORT) {
     // If user cancels download, unpin the file so that we do not sync the file
diff --git a/components/drive/chromeos/sync_client.h b/components/drive/chromeos/sync_client.h
index c9d390d..2972233 100644
--- a/components/drive/chromeos/sync_client.h
+++ b/components/drive/chromeos/sync_client.h
@@ -184,7 +184,7 @@
   // The delay is used for delaying retry of tasks on server errors.
   base::TimeDelta long_delay_;
 
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
diff --git a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java
index 75741cf..7573159 100644
--- a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java
+++ b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java
@@ -129,6 +129,12 @@
             "contextual_search_triggered_by_longpress";
 
     /**
+     * The partner homepage was pressed.
+     */
+    public static final String PARTNER_HOME_PAGE_BUTTON_PRESSED =
+            "partner_home_page_button_pressed";
+
+    /**
      * Do not instantiate.
      */
     private EventConstants() {}
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc
index 7ebd07d..dd4585f 100644
--- a/components/feature_engagement/public/feature_constants.cc
+++ b/components/feature_engagement/public/feature_constants.cc
@@ -43,6 +43,8 @@
     "IPH_ContextualSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kIPHDownloadSettingsFeature{
     "IPH_DownloadSettings", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHHomePageButtonFeature{
+    "IPH_HomePageButton", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_ANDROID)
 
 #if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
diff --git a/components/feature_engagement/public/feature_constants.h b/components/feature_engagement/public/feature_constants.h
index 1bbf81a..ff6fd0b 100644
--- a/components/feature_engagement/public/feature_constants.h
+++ b/components/feature_engagement/public/feature_constants.h
@@ -35,6 +35,7 @@
 extern const base::Feature kIPHContextualSearchOptInFeature;
 extern const base::Feature kIPHContextualSuggestionsFeature;
 extern const base::Feature kIPHDownloadSettingsFeature;
+extern const base::Feature kIPHHomePageButtonFeature;
 #endif  // defined(OS_ANDROID)
 
 #if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
diff --git a/components/feature_engagement/public/feature_list.cc b/components/feature_engagement/public/feature_list.cc
index 79c094a7..dba53bd9 100644
--- a/components/feature_engagement/public/feature_list.cc
+++ b/components/feature_engagement/public/feature_list.cc
@@ -30,6 +30,7 @@
     &kIPHContextualSearchOptInFeature,
     &kIPHContextualSuggestionsFeature,
     &kIPHDownloadSettingsFeature,
+    &kIPHHomePageButtonFeature,
 #endif  // defined(OS_ANDROID)
 #if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
     &kIPHBookmarkFeature,
diff --git a/components/feature_engagement/public/feature_list.h b/components/feature_engagement/public/feature_list.h
index 32423faa..c13e7077 100644
--- a/components/feature_engagement/public/feature_list.h
+++ b/components/feature_engagement/public/feature_list.h
@@ -67,6 +67,7 @@
 DEFINE_VARIATION_PARAM(kIPHContextualSuggestionsFeature,
                        "IPH_ContextualSuggestions");
 DEFINE_VARIATION_PARAM(kIPHDownloadSettingsFeature, "IPH_DownloadSettings");
+DEFINE_VARIATION_PARAM(kIPHHomePageButtonFeature, "IPH_HomePageButton");
 #endif  // defined(OS_ANDROID)
 #if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
 DEFINE_VARIATION_PARAM(kIPHBookmarkFeature, "IPH_Bookmark");
@@ -101,6 +102,7 @@
         VARIATION_ENTRY(kIPHContextualSearchOptInFeature),
         VARIATION_ENTRY(kIPHContextualSuggestionsFeature),
         VARIATION_ENTRY(kIPHDownloadSettingsFeature),
+        VARIATION_ENTRY(kIPHHomePageButtonFeature),
 #elif BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
         VARIATION_ENTRY(kIPHBookmarkFeature),
         VARIATION_ENTRY(kIPHIncognitoWindowFeature),
diff --git a/components/google/core/browser/BUILD.gn b/components/google/core/browser/BUILD.gn
index 96ada90..5585b30 100644
--- a/components/google/core/browser/BUILD.gn
+++ b/components/google/core/browser/BUILD.gn
@@ -30,6 +30,8 @@
     "//components/prefs",
     "//components/strings",
     "//components/url_formatter",
+    "//services/network/public/cpp",
+    "//services/network/public/mojom",
   ]
 }
 
@@ -46,6 +48,9 @@
     "//base",
     "//components/prefs:test_support",
     "//net:test_support",
+    "//services/network:test_support",
+    "//services/network/public/cpp",
+    "//services/network/public/mojom",
     "//testing/gtest",
   ]
 }
diff --git a/components/google/core/browser/DEPS b/components/google/core/browser/DEPS
index afcec3d..1b29f86 100644
--- a/components/google/core/browser/DEPS
+++ b/components/google/core/browser/DEPS
@@ -2,4 +2,6 @@
   "+components/data_use_measurement/core",
   "+components/keyed_service/core",
   "+components/pref_registry",
+  "+services/network/public",
+  "+services/network/test",
 ]
diff --git a/components/google/core/browser/google_url_tracker.cc b/components/google/core/browser/google_url_tracker.cc
index 422d112aa..2adc954 100644
--- a/components/google/core/browser/google_url_tracker.cc
+++ b/components/google/core/browser/google_url_tracker.cc
@@ -21,9 +21,8 @@
 #include "components/prefs/pref_service.h"
 #include "net/base/load_flags.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_status.h"
-
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/simple_url_loader.h"
 
 const char GoogleURLTracker::kDefaultGoogleHomepage[] =
     "https://www.google.com/";
@@ -40,7 +39,6 @@
           mode == ALWAYS_DOT_COM_MODE
               ? kDefaultGoogleHomepage
               : client_->GetPrefs()->GetString(prefs::kLastKnownGoogleURL)),
-      fetcher_id_(0),
       in_startup_sleep_(true),
       already_fetched_(false),
       need_to_fetch_(false),
@@ -80,7 +78,7 @@
 }
 
 void GoogleURLTracker::RequestServerCheck() {
-  if (!fetcher_)
+  if (!simple_loader_)
     SetNeedToFetch();
 }
 
@@ -89,24 +87,24 @@
   return callback_list_.Add(cb);
 }
 
-void GoogleURLTracker::OnURLFetchComplete(const net::URLFetcher* source) {
-  // Delete the fetcher on this function's exit.
-  std::unique_ptr<net::URLFetcher> clean_up_fetcher(std::move(fetcher_));
+void GoogleURLTracker::OnURLLoaderComplete(
+    std::unique_ptr<std::string> response_body) {
+  // Delete the loader.
+  simple_loader_.reset();
 
   // Don't update the URL if the request didn't succeed.
-  if (!source->GetStatus().is_success() || (source->GetResponseCode() != 200)) {
+  if (!response_body) {
     already_fetched_ = false;
     return;
   }
 
-  // See if the response data was valid.  It should be ".google.<TLD>".
-  std::string url_str;
-  source->GetResponseAsString(&url_str);
-  base::TrimWhitespaceASCII(url_str, base::TRIM_ALL, &url_str);
-  if (!base::StartsWith(url_str, ".google.",
+  // See if the response data was valid. It should be ".google.<TLD>".
+  base::TrimWhitespaceASCII(*response_body, base::TRIM_ALL,
+                            response_body.get());
+  if (!base::StartsWith(*response_body, ".google.",
                         base::CompareCase::INSENSITIVE_ASCII))
     return;
-  GURL url("https://www" + url_str);
+  GURL url("https://www" + *response_body);
   if (!url.is_valid() || (url.path().length() > 1) || url.has_query() ||
       url.has_ref() ||
       !google_util::IsGoogleDomainUrl(url, google_util::DISALLOW_SUBDOMAIN,
@@ -132,7 +130,7 @@
 
 void GoogleURLTracker::Shutdown() {
   client_.reset();
-  fetcher_.reset();
+  simple_loader_.reset();
   weak_ptr_factory_.InvalidateWeakPtrs();
   net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
 }
@@ -201,30 +199,30 @@
             "not be Google. But there is no policy that controls navigation "
             "error resolution."
         })");
-  fetcher_ =
-      net::URLFetcher::Create(fetcher_id_, GURL(kSearchDomainCheckURL),
-                              net::URLFetcher::GET, this, traffic_annotation);
-  data_use_measurement::DataUseUserData::AttachToFetcher(
-      fetcher_.get(),
-      data_use_measurement::DataUseUserData::GOOGLE_URL_TRACKER);
-  ++fetcher_id_;
-  // We don't want this fetch to set new entries in the cache or cookies, lest
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url = GURL(kSearchDomainCheckURL);
+  // We don't want this load to set new entries in the cache or cookies, lest
   // we alarm the user.
-  fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE |
-                         net::LOAD_DO_NOT_SAVE_COOKIES);
-  fetcher_->SetRequestContext(client_->GetRequestContext());
-
-  // Configure to retry at most kMaxRetries times for 5xx errors.
+  resource_request->load_flags =
+      (net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SAVE_COOKIES);
+  simple_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
+                                                    traffic_annotation);
+  // Configure to retry at most kMaxRetries times for 5xx errors and network
+  // changes.
+  // A network change can propagate through Chrome in various stages, so it's
+  // possible for this code to be reached via OnNetworkChanged(), and then have
+  // the fetch we kick off be canceled due to e.g. the DNS server changing at a
+  // later time. In general it's not possible to ensure that by the time we
+  // reach here any requests we start won't be canceled in this fashion, so
+  // retrying is the best we can do.
   static const int kMaxRetries = 5;
-  fetcher_->SetMaxRetriesOn5xx(kMaxRetries);
-
-  // Also retry kMaxRetries times on network change errors. A network change can
-  // propagate through Chrome in various stages, so it's possible for this code
-  // to be reached via OnNetworkChanged(), and then have the fetch we kick off
-  // be canceled due to e.g. the DNS server changing at a later time. In general
-  // it's not possible to ensure that by the time we reach here any requests we
-  // start won't be canceled in this fashion, so retrying is the best we can do.
-  fetcher_->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries);
-
-  fetcher_->Start();
+  simple_loader_->SetRetryOptions(
+      kMaxRetries,
+      network::SimpleURLLoader::RetryMode::RETRY_ON_5XX |
+          network::SimpleURLLoader::RetryMode::RETRY_ON_NETWORK_CHANGE);
+  simple_loader_->DownloadToString(
+      client_->GetURLLoaderFactory(),
+      base::BindOnce(&GoogleURLTracker::OnURLLoaderComplete,
+                     base::Unretained(this)),
+      2 * 1024 /* max_body_size */);
 }
diff --git a/components/google/core/browser/google_url_tracker.h b/components/google/core/browser/google_url_tracker.h
index bcaba948..c856fac 100644
--- a/components/google/core/browser/google_url_tracker.h
+++ b/components/google/core/browser/google_url_tracker.h
@@ -15,14 +15,16 @@
 #include "components/google/core/browser/google_url_tracker_client.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "net/base/network_change_notifier.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_fetcher_delegate.h"
 #include "url/gurl.h"
 
 namespace user_prefs {
 class PrefRegistrySyncable;
 }
 
+namespace network {
+class SimpleURLLoader;
+}  // namespace network
+
 // This object is responsible for checking the Google URL once per network
 // change.  The current value is saved to prefs.
 //
@@ -33,8 +35,7 @@
 // performed (ever) unless at least one consumer registers interest by calling
 // RequestServerCheck().
 class GoogleURLTracker
-    : public net::URLFetcherDelegate,
-      public net::NetworkChangeNotifier::NetworkChangeObserver,
+    : public net::NetworkChangeNotifier::NetworkChangeObserver,
       public KeyedService {
  public:
   // Callback that is called when the Google URL is updated.
@@ -93,8 +94,7 @@
 
   static const char kSearchDomainCheckURL[];
 
-  // net::URLFetcherDelegate:
-  void OnURLFetchComplete(const net::URLFetcher* source) override;
+  void OnURLLoaderComplete(std::unique_ptr<std::string> response_body);
 
   // NetworkChangeNotifier::NetworkChangeObserver:
   void OnNetworkChanged(
@@ -119,8 +119,7 @@
   std::unique_ptr<GoogleURLTrackerClient> client_;
 
   GURL google_url_;
-  std::unique_ptr<net::URLFetcher> fetcher_;
-  int fetcher_id_;
+  std::unique_ptr<network::SimpleURLLoader> simple_loader_;
   bool in_startup_sleep_;  // True if we're in the five-second "no fetching"
                            // period that begins at browser start.
   bool already_fetched_;   // True if we've already fetched a URL once this run;
diff --git a/components/google/core/browser/google_url_tracker_client.h b/components/google/core/browser/google_url_tracker_client.h
index 58f51a7..0ab7028 100644
--- a/components/google/core/browser/google_url_tracker_client.h
+++ b/components/google/core/browser/google_url_tracker_client.h
@@ -11,8 +11,10 @@
 class GoogleURLTracker;
 class PrefService;
 
-namespace net {
-class URLRequestContextGetter;
+namespace network {
+namespace mojom {
+class URLLoaderFactory;
+}
 }
 
 // Interface by which GoogleURLTracker communicates with its embedder.
@@ -32,9 +34,8 @@
   // Returns the PrefService that the GoogleURLTracker should use.
   virtual PrefService* GetPrefs() = 0;
 
-  // Returns the URL request context information that the GoogleURLTracker
-  // should use.
-  virtual net::URLRequestContextGetter* GetRequestContext() = 0;
+  // Returns the URL loader factory that the GoogleURLTracker should use.
+  virtual network::mojom::URLLoaderFactory* GetURLLoaderFactory() = 0;
 
  protected:
   GoogleURLTracker* google_url_tracker() { return google_url_tracker_; }
diff --git a/components/google/core/browser/google_url_tracker_unittest.cc b/components/google/core/browser/google_url_tracker_unittest.cc
index e09db9a..4347985 100644
--- a/components/google/core/browser/google_url_tracker_unittest.cc
+++ b/components/google/core/browser/google_url_tracker_unittest.cc
@@ -10,6 +10,7 @@
 
 #include "base/macros.h"
 #include "base/run_loop.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/google/core/browser/google_pref_names.h"
@@ -17,9 +18,10 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/testing_pref_service.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_test_util.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -71,25 +73,29 @@
 
 class TestGoogleURLTrackerClient : public GoogleURLTrackerClient {
  public:
-  explicit TestGoogleURLTrackerClient(PrefService* prefs_);
+  TestGoogleURLTrackerClient(
+      PrefService* prefs_,
+      network::TestURLLoaderFactory* test_url_loader_factory);
   ~TestGoogleURLTrackerClient() override;
 
   bool IsBackgroundNetworkingEnabled() override;
   PrefService* GetPrefs() override;
-  net::URLRequestContextGetter* GetRequestContext() override;
+  network::mojom::URLLoaderFactory* GetURLLoaderFactory() override;
 
  private:
   PrefService* prefs_;
-  scoped_refptr<net::TestURLRequestContextGetter> request_context_;
+  scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(TestGoogleURLTrackerClient);
 };
 
-TestGoogleURLTrackerClient::TestGoogleURLTrackerClient(PrefService* prefs)
+TestGoogleURLTrackerClient::TestGoogleURLTrackerClient(
+    PrefService* prefs,
+    network::TestURLLoaderFactory* test_url_loader_factory)
     : prefs_(prefs),
-      request_context_(new net::TestURLRequestContextGetter(
-          base::ThreadTaskRunnerHandle::Get())) {
-}
+      test_shared_loader_factory_(
+          base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+              test_url_loader_factory)) {}
 
 TestGoogleURLTrackerClient::~TestGoogleURLTrackerClient() {
 }
@@ -102,11 +108,11 @@
   return prefs_;
 }
 
-net::URLRequestContextGetter* TestGoogleURLTrackerClient::GetRequestContext() {
-  return request_context_.get();
+network::mojom::URLLoaderFactory*
+TestGoogleURLTrackerClient::GetURLLoaderFactory() {
+  return test_shared_loader_factory_.get();
 }
 
-
 }  // namespace
 
 // GoogleURLTrackerTest -------------------------------------------------------
@@ -120,7 +126,6 @@
   void SetUp() override;
   void TearDown() override;
 
-  net::TestURLFetcher* GetFetcher();
   void MockSearchDomainCheckResponse(const std::string& domain);
   void RequestServerCheck();
   void FinishSleep();
@@ -131,18 +136,24 @@
   GURL google_url() const { return google_url_tracker_->google_url(); }
   bool listener_notified() const { return listener_.notified(); }
   void clear_listener_notified() { listener_.clear_notified(); }
+  bool handled_request() const { return handled_request_; }
+
+  GoogleURLTrackerClient* client() const { return client_; }
 
  private:
   base::test::ScopedTaskEnvironment scoped_task_environment_;
   TestingPrefServiceSimple prefs_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
 
   // Creating this allows us to call
   // net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests().
   std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
-  net::TestURLFetcherFactory fetcher_factory_;
   GoogleURLTrackerClient* client_;
+
   std::unique_ptr<GoogleURLTracker> google_url_tracker_;
   TestCallbackListener listener_;
+
+  bool handled_request_ = false;
 };
 
 GoogleURLTrackerTest::GoogleURLTrackerTest() {
@@ -158,7 +169,7 @@
   network_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock());
   // Ownership is passed to google_url_tracker_, but a weak pointer is kept;
   // this is safe since GoogleURLTracker keeps the client for its lifetime.
-  client_ = new TestGoogleURLTrackerClient(&prefs_);
+  client_ = new TestGoogleURLTrackerClient(&prefs_, &test_url_loader_factory_);
   std::unique_ptr<GoogleURLTrackerClient> client(client_);
   google_url_tracker_.reset(new GoogleURLTracker(
       std::move(client), GoogleURLTracker::ALWAYS_DOT_COM_MODE));
@@ -168,33 +179,27 @@
   google_url_tracker_->Shutdown();
 }
 
-net::TestURLFetcher* GoogleURLTrackerTest::GetFetcher() {
-  // This will return the last fetcher created.  If no fetchers have been
-  // created, we'll pass GetFetcherByID() "-1", and it will return NULL.
-  return fetcher_factory_.GetFetcherByID(google_url_tracker_->fetcher_id_ - 1);
-}
-
 void GoogleURLTrackerTest::MockSearchDomainCheckResponse(
     const std::string& domain) {
-  net::TestURLFetcher* fetcher = GetFetcher();
-  if (!fetcher)
-    return;
-  fetcher_factory_.RemoveFetcherFromMap(fetcher->id());
-  fetcher->set_url(GURL(GoogleURLTracker::kSearchDomainCheckURL));
-  fetcher->set_response_code(200);
-  fetcher->SetResponseString(domain);
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
-  // At this point, |fetcher| is deleted.
+  handled_request_ = false;
+  test_url_loader_factory_.SetInterceptor(
+      base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
+        handled_request_ = true;
+      }));
+  test_url_loader_factory_.AddResponse(GoogleURLTracker::kSearchDomainCheckURL,
+                                       domain);
 }
 
 void GoogleURLTrackerTest::RequestServerCheck() {
   if (!listener_.HasRegisteredCallback())
     listener_.RegisterCallback(google_url_tracker_.get());
   google_url_tracker_->SetNeedToFetch();
+  base::RunLoop().RunUntilIdle();
 }
 
 void GoogleURLTrackerTest::FinishSleep() {
   google_url_tracker_->FinishSleep();
+  base::RunLoop().RunUntilIdle();
 }
 
 void GoogleURLTrackerTest::NotifyNetworkChanged() {
@@ -211,35 +216,37 @@
   EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
   FinishSleep();
   // No one called RequestServerCheck() so nothing should have happened.
-  EXPECT_FALSE(GetFetcher());
+  EXPECT_FALSE(handled_request());
   MockSearchDomainCheckResponse(".google.co.uk");
   EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
   EXPECT_FALSE(listener_notified());
 }
 
 TEST_F(GoogleURLTrackerTest, Update) {
+  MockSearchDomainCheckResponse(".google.co.uk");
+
   RequestServerCheck();
-  EXPECT_FALSE(GetFetcher());
+  EXPECT_FALSE(handled_request());
   EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
   EXPECT_FALSE(listener_notified());
 
   FinishSleep();
-  MockSearchDomainCheckResponse(".google.co.uk");
   EXPECT_EQ(GURL("https://www.google.co.uk/"), google_url());
   EXPECT_TRUE(listener_notified());
 }
 
 TEST_F(GoogleURLTrackerTest, DontUpdateWhenUnchanged) {
+  MockSearchDomainCheckResponse(".google.co.uk");
+
   GURL original_google_url("https://www.google.co.uk/");
   set_google_url(original_google_url);
 
   RequestServerCheck();
-  EXPECT_FALSE(GetFetcher());
+  EXPECT_FALSE(handled_request());
   EXPECT_EQ(original_google_url, google_url());
   EXPECT_FALSE(listener_notified());
 
   FinishSleep();
-  MockSearchDomainCheckResponse(".google.co.uk");
   EXPECT_EQ(original_google_url, google_url());
   // No one should be notified, because the new URL matches the old.
   EXPECT_FALSE(listener_notified());
@@ -250,107 +257,107 @@
   set_google_url(original_google_url);
 
   RequestServerCheck();
-  EXPECT_FALSE(GetFetcher());
+  EXPECT_FALSE(handled_request());
   EXPECT_EQ(original_google_url, google_url());
   EXPECT_FALSE(listener_notified());
 
   // Old-style URL string.
-  FinishSleep();
   MockSearchDomainCheckResponse("https://www.google.com/");
+  FinishSleep();
   EXPECT_EQ(original_google_url, google_url());
   EXPECT_FALSE(listener_notified());
 
   // Not a Google domain.
-  FinishSleep();
   MockSearchDomainCheckResponse(".google.evil.com");
+  FinishSleep();
   EXPECT_EQ(original_google_url, google_url());
   EXPECT_FALSE(listener_notified());
 
   // Doesn't start with .google.
-  NotifyNetworkChanged();
   MockSearchDomainCheckResponse(".mail.google.com");
+  NotifyNetworkChanged();
   EXPECT_EQ(original_google_url, google_url());
   EXPECT_FALSE(listener_notified());
 
   // Non-empty path.
-  NotifyNetworkChanged();
   MockSearchDomainCheckResponse(".google.com/search");
+  NotifyNetworkChanged();
   EXPECT_EQ(original_google_url, google_url());
   EXPECT_FALSE(listener_notified());
 
   // Non-empty query.
-  NotifyNetworkChanged();
   MockSearchDomainCheckResponse(".google.com/?q=foo");
+  NotifyNetworkChanged();
   EXPECT_EQ(original_google_url, google_url());
   EXPECT_FALSE(listener_notified());
 
   // Non-empty ref.
-  NotifyNetworkChanged();
   MockSearchDomainCheckResponse(".google.com/#anchor");
+  NotifyNetworkChanged();
   EXPECT_EQ(original_google_url, google_url());
   EXPECT_FALSE(listener_notified());
 
   // Complete garbage.
-  NotifyNetworkChanged();
   MockSearchDomainCheckResponse("HJ)*qF)_*&@f1");
+  NotifyNetworkChanged();
   EXPECT_EQ(original_google_url, google_url());
   EXPECT_FALSE(listener_notified());
 }
 
 TEST_F(GoogleURLTrackerTest, RefetchOnNetworkChange) {
+  MockSearchDomainCheckResponse(".google.co.uk");
   RequestServerCheck();
   FinishSleep();
-  MockSearchDomainCheckResponse(".google.co.uk");
   EXPECT_EQ(GURL("https://www.google.co.uk/"), google_url());
   EXPECT_TRUE(listener_notified());
   clear_listener_notified();
 
-  NotifyNetworkChanged();
   MockSearchDomainCheckResponse(".google.co.in");
+  NotifyNetworkChanged();
   EXPECT_EQ(GURL("https://www.google.co.in/"), google_url());
   EXPECT_TRUE(listener_notified());
 }
 
 TEST_F(GoogleURLTrackerTest, DontRefetchWhenNoOneRequestsCheck) {
+  MockSearchDomainCheckResponse(".google.co.uk");
   FinishSleep();
   NotifyNetworkChanged();
   // No one called RequestServerCheck() so nothing should have happened.
-  EXPECT_FALSE(GetFetcher());
-  MockSearchDomainCheckResponse(".google.co.uk");
+  EXPECT_FALSE(handled_request());
   EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
   EXPECT_FALSE(listener_notified());
 }
 
 TEST_F(GoogleURLTrackerTest, FetchOnLateRequest) {
+  MockSearchDomainCheckResponse(".google.co.jp");
   FinishSleep();
   NotifyNetworkChanged();
-  MockSearchDomainCheckResponse(".google.co.jp");
 
+  MockSearchDomainCheckResponse(".google.co.uk");
   RequestServerCheck();
   // The first request for a check should trigger a fetch if it hasn't happened
   // already.
-  MockSearchDomainCheckResponse(".google.co.uk");
   EXPECT_EQ(GURL("https://www.google.co.uk/"), google_url());
   EXPECT_TRUE(listener_notified());
 }
 
 TEST_F(GoogleURLTrackerTest, DontFetchTwiceOnLateRequests) {
+  MockSearchDomainCheckResponse(".google.co.jp");
   FinishSleep();
   NotifyNetworkChanged();
-  MockSearchDomainCheckResponse(".google.co.jp");
 
+  MockSearchDomainCheckResponse(".google.co.uk");
   RequestServerCheck();
   // The first request for a check should trigger a fetch if it hasn't happened
   // already.
-  MockSearchDomainCheckResponse(".google.co.uk");
   EXPECT_EQ(GURL("https://www.google.co.uk/"), google_url());
   EXPECT_TRUE(listener_notified());
   clear_listener_notified();
 
+  MockSearchDomainCheckResponse(".google.co.in");
   RequestServerCheck();
   // The second request should be ignored.
-  EXPECT_FALSE(GetFetcher());
-  MockSearchDomainCheckResponse(".google.co.in");
+  EXPECT_FALSE(handled_request());
   EXPECT_EQ(GURL("https://www.google.co.uk/"), google_url());
   EXPECT_FALSE(listener_notified());
 }
diff --git a/components/ntp_tiles/popular_sites_impl.cc b/components/ntp_tiles/popular_sites_impl.cc
index b0fb927..4282e12 100644
--- a/components/ntp_tiles/popular_sites_impl.cc
+++ b/components/ntp_tiles/popular_sites_impl.cc
@@ -33,6 +33,8 @@
 #include "net/base/load_flags.h"
 #include "net/http/http_status_code.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_status.h"
 
 #if defined(OS_ANDROID) || defined(OS_IOS)
 #include "base/json/json_reader.h"
diff --git a/components/omnibox/browser/autocomplete_provider_unittest.cc b/components/omnibox/browser/autocomplete_provider_unittest.cc
index 05fb984..30816e0 100644
--- a/components/omnibox/browser/autocomplete_provider_unittest.cc
+++ b/components/omnibox/browser/autocomplete_provider_unittest.cc
@@ -32,6 +32,7 @@
 #include "components/search_engines/template_url.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/search_engines/template_url_service_client.h"
+#include "net/url_request/url_request.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/metrics_proto/omnibox_event.pb.h"
 
diff --git a/components/omnibox/browser/keyword_provider_unittest.cc b/components/omnibox/browser/keyword_provider_unittest.cc
index 55cf3c7..9b4418cb 100644
--- a/components/omnibox/browser/keyword_provider_unittest.cc
+++ b/components/omnibox/browser/keyword_provider_unittest.cc
@@ -24,6 +24,7 @@
 #include "components/search_engines/template_url_service.h"
 #include "components/variations/entropy_provider.h"
 #include "components/variations/variations_associated_data.h"
+#include "net/url_request/url_request.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/metrics_proto/omnibox_event.pb.h"
diff --git a/components/security_interstitials/core/browser/resources/interstitial_large.js b/components/security_interstitials/core/browser/resources/interstitial_large.js
index 30a716ac..d57ec694 100644
--- a/components/security_interstitials/core/browser/resources/interstitial_large.js
+++ b/components/security_interstitials/core/browser/resources/interstitial_large.js
@@ -130,6 +130,8 @@
 
   if (!ssl || !showRecurrentErrorParagraph) {
     $('recurrent-error-message').classList.add(HIDDEN_CLASS);
+  } else {
+    $('body').classList.add('showing-recurrent-error-message');
   }
 
   if ($('diagnostic-link')) {
diff --git a/components/security_interstitials/core/common/resources/interstitial_common.css b/components/security_interstitials/core/common/resources/interstitial_common.css
index 76380d9..71e5ace4 100644
--- a/components/security_interstitials/core/common/resources/interstitial_common.css
+++ b/components/security_interstitials/core/common/resources/interstitial_common.css
@@ -456,3 +456,13 @@
     padding-right: 0;
   }
 }
+
+#recurrent-error-message {
+  background: #efefef;
+  padding: 14px;
+  margin-top: 7px;
+}
+
+.showing-recurrent-error-message #extended-reporting-opt-in {
+  margin-top: 14px;
+}
diff --git a/components/sync/driver/about_sync_util.cc b/components/sync/driver/about_sync_util.cc
index cc50751..3da73ab 100644
--- a/components/sync/driver/about_sync_util.cc
+++ b/components/sync/driver/about_sync_util.cc
@@ -56,6 +56,7 @@
 const char kUserEventsVisibilityCallback[] =
     "chrome.sync.userEventsVisibilityCallback";
 const char kWriteUserEvent[] = "writeUserEvent";
+const char kTriggerRefresh[] = "triggerRefresh";
 
 // Other strings.
 const char kCommit[] = "commit";
diff --git a/components/sync/driver/about_sync_util.h b/components/sync/driver/about_sync_util.h
index 9424c426..d16ffb17 100644
--- a/components/sync/driver/about_sync_util.h
+++ b/components/sync/driver/about_sync_util.h
@@ -53,6 +53,7 @@
 extern const char kSetIncludeSpecifics[];
 extern const char kUserEventsVisibilityCallback[];
 extern const char kWriteUserEvent[];
+extern const char kTriggerRefresh[];
 
 // Other strings.
 // Must match the constants used in the resource files.
diff --git a/components/sync/driver/resources/about.html b/components/sync/driver/resources/about.html
index d0ffbae..94e6e126 100644
--- a/components/sync/driver/resources/about.html
+++ b/components/sync/driver/resources/about.html
@@ -29,6 +29,7 @@
     <h2 style="display:inline-block">Sync Protocol Log</h2>
     <input type="checkbox" id="capture-specifics">
     <label for="capture-specifics">Capture Specifics</label>
+    <button id="trigger-refresh">Trigger GetUpdates</button>
     <div id="traffic-event-container">
       <div class="traffic-event-entry"
            jsselect="events"
diff --git a/components/sync/driver/resources/about.js b/components/sync/driver/resources/about.js
index c65147d..12b8761 100644
--- a/components/sync/driver/resources/about.js
+++ b/components/sync/driver/resources/about.js
@@ -122,6 +122,11 @@
 
     // Make the prototype jscontent element disappear.
     jstProcess({}, $('traffic-event-container'));
+
+    var triggerRefreshButton = $('trigger-refresh');
+    triggerRefreshButton.addEventListener('click', function(event) {
+      chrome.sync.triggerRefresh();
+    });
   }
 
   /**
diff --git a/components/sync/driver/resources/chrome_sync.js b/components/sync/driver/resources/chrome_sync.js
index 481174e..f996b15 100644
--- a/components/sync/driver/resources/chrome_sync.js
+++ b/components/sync/driver/resources/chrome_sync.js
@@ -105,6 +105,13 @@
   };
 
   /**
+   * Triggers a GetUpdates call for all enabled datatypes.
+   */
+  var triggerRefresh = function() {
+    chrome.send('triggerRefresh');
+  };
+
+  /**
    * Counter to uniquely identify requests while they're in progress.
    * Used in the implementation of GetAllNodes.
    */
@@ -153,5 +160,6 @@
     requestUserEventsVisibility: requestUserEventsVisibility,
     setIncludeSpecifics: setIncludeSpecifics,
     writeUserEvent: writeUserEvent,
+    triggerRefresh: triggerRefresh,
   };
 });
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index c646068..7299492 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1175,8 +1175,6 @@
     "notifications/notification_event_dispatcher_impl.h",
     "notifications/notification_id_generator.cc",
     "notifications/notification_id_generator.h",
-    "notifications/notification_message_filter.cc",
-    "notifications/notification_message_filter.h",
     "notifications/platform_notification_context_impl.cc",
     "notifications/platform_notification_context_impl.h",
     "origin_manifest/origin_manifest_parser.cc",
@@ -1367,6 +1365,8 @@
     "renderer_host/media/media_stream_track_metrics_host.h",
     "renderer_host/media/media_stream_ui_proxy.cc",
     "renderer_host/media/media_stream_ui_proxy.h",
+    "renderer_host/media/old_render_frame_audio_output_stream_factory.cc",
+    "renderer_host/media/old_render_frame_audio_output_stream_factory.h",
     "renderer_host/media/peer_connection_tracker_host.cc",
     "renderer_host/media/peer_connection_tracker_host.h",
     "renderer_host/media/render_frame_audio_input_stream_factory.cc",
@@ -2319,8 +2319,6 @@
       "context_factory.cc",
       "renderer_host/browser_compositor_view_mac.h",
       "renderer_host/browser_compositor_view_mac.mm",
-      "renderer_host/compositor_resize_lock.cc",
-      "renderer_host/compositor_resize_lock.h",
       "renderer_host/delegated_frame_host.cc",
       "renderer_host/delegated_frame_host.h",
     ]
diff --git a/content/browser/background_sync/background_sync_context.cc b/content/browser/background_sync/background_sync_context.cc
index 625ae34..fc77d81 100644
--- a/content/browser/background_sync/background_sync_context.cc
+++ b/content/browser/background_sync/background_sync_context.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
 #include "content/browser/background_sync/background_sync_manager.h"
 #include "content/browser/background_sync/background_sync_service_impl.h"
@@ -86,9 +85,9 @@
     mojo::InterfaceRequest<blink::mojom::BackgroundSyncService> request) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(background_sync_manager_);
-  BackgroundSyncServiceImpl* service =
-      new BackgroundSyncServiceImpl(this, std::move(request));
-  services_[service] = base::WrapUnique(service);
+  auto service =
+      std::make_unique<BackgroundSyncServiceImpl>(this, std::move(request));
+  services_[service.get()] = std::move(service);
 }
 
 void BackgroundSyncContext::ShutdownOnIO() {
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h
index d0e0a40..350acc7 100644
--- a/content/browser/bad_message.h
+++ b/content/browser/bad_message.h
@@ -227,6 +227,7 @@
   SYNC_COMPOSITOR_NO_BEGIN_FRAME = 199,
   WEBUI_BAD_HOST_ACCESS = 200,
   RFMF_BLOB_URL_TOKEN_FOR_NON_BLOB_URL = 201,
+  PERMISSION_SERVICE_BAD_PERMISSION_DESCRIPTOR = 202,
 
   // Please add new elements here. The naming convention is abbreviated class
   // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 2cc2920..77711c8 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -235,6 +235,40 @@
 }
 
 // static
+void RenderFrameDevToolsAgentHost::OnSignedExchangeCertificateRequestSent(
+    FrameTreeNode* frame_tree_node,
+    const base::UnguessableToken& request_id,
+    const base::UnguessableToken& loader_id,
+    const network::ResourceRequest& request) {
+  DispatchToAgents(frame_tree_node, &protocol::NetworkHandler::RequestSent,
+                   request_id.ToString(), loader_id.ToString(), request,
+                   protocol::Network::Initiator::TypeEnum::Other);
+}
+
+// static
+void RenderFrameDevToolsAgentHost::OnSignedExchangeCertificateResponseReceived(
+    FrameTreeNode* frame_tree_node,
+    const base::UnguessableToken& request_id,
+    const base::UnguessableToken& loader_id,
+    const GURL& url,
+    const network::ResourceResponseHead& head) {
+  DispatchToAgents(frame_tree_node, &protocol::NetworkHandler::ResponseReceived,
+                   request_id.ToString(), loader_id.ToString(), url,
+                   protocol::Page::ResourceTypeEnum::Other, head,
+                   protocol::Maybe<std::string>());
+}
+
+// static
+void RenderFrameDevToolsAgentHost::OnSignedExchangeCertificateRequestCompleted(
+    FrameTreeNode* frame_tree_node,
+    const base::UnguessableToken& request_id,
+    const network::URLLoaderCompletionStatus& status) {
+  DispatchToAgents(frame_tree_node, &protocol::NetworkHandler::LoadingComplete,
+                   request_id.ToString(),
+                   protocol::Page::ResourceTypeEnum::Other, status);
+}
+
+// static
 std::vector<std::unique_ptr<NavigationThrottle>>
 RenderFrameDevToolsAgentHost::CreateNavigationThrottles(
     NavigationHandleImpl* navigation_handle) {
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h
index 72c50b8..6028dd96 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -94,6 +94,21 @@
       base::Optional<const base::UnguessableToken> devtools_navigation_token,
       const GURL& outer_request_url,
       const network::ResourceResponseHead& outer_response);
+  static void OnSignedExchangeCertificateRequestSent(
+      FrameTreeNode* frame_tree_node,
+      const base::UnguessableToken& request_id,
+      const base::UnguessableToken& loader_id,
+      const network::ResourceRequest& request);
+  static void OnSignedExchangeCertificateResponseReceived(
+      FrameTreeNode* frame_tree_node,
+      const base::UnguessableToken& request_id,
+      const base::UnguessableToken& loader_id,
+      const GURL& url,
+      const network::ResourceResponseHead& head);
+  static void OnSignedExchangeCertificateRequestCompleted(
+      FrameTreeNode* frame_tree_node,
+      const base::UnguessableToken& request_id,
+      const network::URLLoaderCompletionStatus& status);
 
   static std::vector<std::unique_ptr<NavigationThrottle>>
   CreateNavigationThrottles(NavigationHandleImpl* navigation_handle);
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index ef44adb..ea9d41b 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -974,8 +974,7 @@
   void RunResumptionTest(
       const download::DownloadItem::ReceivedSlices& received_slices,
       int64_t total_length,
-      size_t expected_request_count,
-      bool support_partial_response) {
+      size_t expected_request_count) {
     EXPECT_TRUE(
         base::FeatureList::IsEnabled(download::features::kParallelDownloading));
     GURL url = TestDownloadHttpResponse::GetNextURLForDownload();
@@ -984,7 +983,6 @@
     parameters.etag = "ABC";
     parameters.size = total_length;
     parameters.last_modified = std::string();
-    parameters.support_partial_response = support_partial_response;
     // Needed to specify HTTP connection type to create parallel download.
     parameters.connection_type = net::HttpResponseInfo::CONNECTION_INFO_HTTP1_1;
     TestDownloadHttpResponse::StartServing(parameters, server_url);
@@ -1001,17 +999,12 @@
     // Resume the parallel download with sparse file and received slices data.
     download->Resume();
     WaitForCompletion(download);
-    // TODO(qinmin): count the failed partial responses in DownloadJob when
-    // support_partial_response is false. EmbeddedTestServer doesn't know
-    // whether completing or canceling the response will come first.
-    if (support_partial_response) {
-      test_response_handler()->WaitUntilCompletion(expected_request_count);
+    test_response_handler()->WaitUntilCompletion(expected_request_count);
 
-      // Verify number of requests sent to the server.
-      const TestDownloadResponseHandler::CompletedRequests& completed_requests =
-          test_response_handler()->completed_requests();
-      EXPECT_EQ(expected_request_count, completed_requests.size());
-    }
+    // Verify number of requests sent to the server.
+    const TestDownloadResponseHandler::CompletedRequests& completed_requests =
+        test_response_handler()->completed_requests();
+    EXPECT_EQ(expected_request_count, completed_requests.size());
 
     // Verify download content on disk.
     ReadAndVerifyFileContents(parameters.pattern_generator_seed,
@@ -1033,29 +1026,22 @@
     parameters.connection_type = net::HttpResponseInfo::CONNECTION_INFO_HTTP1_1;
     TestRequestPauseHandler request_pause_handler;
     parameters.on_pause_handler = request_pause_handler.GetOnPauseHandler();
-    // Send some data for the first request and pause it so download won't
-    // complete before other parallel requests are created.
     parameters.pause_offset = DownloadRequestCore::kDownloadByteStreamSize;
     TestDownloadHttpResponse::StartServing(parameters, server_url);
 
     download::DownloadItem* download =
         StartDownloadAndReturnItem(shell(), server_url);
-    // TODO(qinmin): wait for the failed partial responses in DownloadJob.
-    // Waiting for the completed test server requests is unsafe. This is because
-    // completing or canceling the response first all depends on the internal
-    // write buffer size.
-    if (parameters.support_partial_response)
-      test_response_handler()->WaitUntilCompletion(2u);
+    // Send some data for the first request and pause it so download won't
+    // complete before other parallel requests are created.
+    test_response_handler()->WaitUntilCompletion(2u);
 
     // Now resume the first request.
     request_pause_handler.Resume();
     WaitForCompletion(download);
-    if (parameters.support_partial_response) {
-      test_response_handler()->WaitUntilCompletion(3u);
-      const TestDownloadResponseHandler::CompletedRequests& completed_requests =
-          test_response_handler()->completed_requests();
-      EXPECT_EQ(3u, completed_requests.size());
-    }
+    test_response_handler()->WaitUntilCompletion(3u);
+    const TestDownloadResponseHandler::CompletedRequests& completed_requests =
+        test_response_handler()->completed_requests();
+    EXPECT_EQ(kTestRequestCount, static_cast<int>(completed_requests.size()));
     ReadAndVerifyFileContents(parameters.pattern_generator_seed,
                               parameters.size, download->GetTargetFilePath());
   }
@@ -3196,17 +3182,6 @@
   RunCompletionTest(parameters);
 }
 
-// The server will send Accept-Ranges header without partial response.
-IN_PROC_BROWSER_TEST_F(ParallelDownloadTest, NoPartialResponse) {
-  TestDownloadHttpResponse::Parameters parameters;
-  parameters.etag = "ABC";
-  parameters.size = 5097152;
-  parameters.support_byte_ranges = true;
-  parameters.support_partial_response = false;
-
-  RunCompletionTest(parameters);
-}
-
 // Verify parallel download resumption.
 IN_PROC_BROWSER_TEST_F(ParallelDownloadTest, Resumption) {
   // Create the received slices data, the last request is not finished and the
@@ -3217,8 +3192,7 @@
       download::DownloadItem::ReceivedSlice(2000000, 1000,
                                             false /* finished */)};
 
-  RunResumptionTest(received_slices, 3000000, kTestRequestCount,
-                    true /* support_partial_response */);
+  RunResumptionTest(received_slices, 3000000, kTestRequestCount);
 }
 
 // Verifies that if the last slice is finished, parallel download resumption
@@ -3233,8 +3207,7 @@
 
   // The server shouldn't receive an additional request, since the last slice
   // is marked as finished.
-  RunResumptionTest(received_slices, 3000000, kTestRequestCount - 1,
-                    true /* support_partial_response */);
+  RunResumptionTest(received_slices, 3000000, kTestRequestCount - 1);
 }
 
 // Verifies that if the last slice is finished, but the database record is not
@@ -3250,23 +3223,7 @@
 
   // Client will send an out of range request where server will send back HTTP
   // range not satisfied, and download can complete.
-  RunResumptionTest(received_slices, 3000000, kTestRequestCount,
-                    true /* support_partial_response */);
-}
-
-// Verify that if server doesn't support partial response, resuming a parallel
-// download should complete the download.
-IN_PROC_BROWSER_TEST_F(ParallelDownloadTest, ResumptionNoPartialResponse) {
-  // Create the received slices data, the last request is not finished and the
-  // server will send more data to finish the last slice.
-  std::vector<download::DownloadItem::ReceivedSlice> received_slices = {
-      download::DownloadItem::ReceivedSlice(0, 1000),
-      download::DownloadItem::ReceivedSlice(1000000, 1000),
-      download::DownloadItem::ReceivedSlice(2000000, 1000,
-                                            false /* finished */)};
-
-  RunResumptionTest(received_slices, 3000000, kTestRequestCount,
-                    false /* support_partial_response */);
+  RunResumptionTest(received_slices, 3000000, kTestRequestCount);
 }
 
 // Test to verify that the browser-side enforcement of X-Frame-Options does
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index f289fb7..54f4e92 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -3785,7 +3785,7 @@
     GetContentClient()
         ->browser()
         ->RegisterNonNetworkSubresourceURLLoaderFactories(
-            this, common_params.url, &non_network_url_loader_factories_);
+            process_->GetID(), routing_id_, &non_network_url_loader_factories_);
 
     for (auto& factory : non_network_url_loader_factories_) {
       network::mojom::URLLoaderFactoryPtrInfo factory_proxy_info;
@@ -4587,12 +4587,21 @@
 
 void RenderFrameHostImpl::CreateAudioOutputStreamFactory(
     mojom::RendererAudioOutputStreamFactoryRequest request) {
-  RendererAudioOutputStreamFactoryContext* factory_context =
-      GetProcess()->GetRendererAudioOutputStreamFactoryContext();
-  DCHECK(factory_context);
-  audio_output_stream_factory_ =
-      RenderFrameAudioOutputStreamFactoryHandle::CreateFactory(
-          factory_context, GetRoutingID(), std::move(request));
+  if (base::FeatureList::IsEnabled(features::kAudioServiceAudioStreams)) {
+    media::AudioSystem* audio_system =
+        BrowserMainLoop::GetInstance()->audio_system();
+    MediaStreamManager* media_stream_manager =
+        BrowserMainLoop::GetInstance()->media_stream_manager();
+    audio_service_audio_output_stream_factory_.emplace(
+        this, audio_system, media_stream_manager, std::move(request));
+  } else {
+    RendererAudioOutputStreamFactoryContext* factory_context =
+        GetProcess()->GetRendererAudioOutputStreamFactoryContext();
+    DCHECK(factory_context);
+    in_content_audio_output_stream_factory_ =
+        RenderFrameAudioOutputStreamFactoryHandle::CreateFactory(
+            factory_context, GetRoutingID(), std::move(request));
+  }
 }
 
 #if BUILDFLAG(ENABLE_WEBRTC)
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index dca501f..ac2a5ab 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -31,6 +31,7 @@
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/loader/global_routing_id.h"
+#include "content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory.h"
 #include "content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h"
 #include "content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h"
 #include "content/browser/site_instance_impl.h"
@@ -1421,7 +1422,13 @@
   TextSurroundingSelectionCallback text_surrounding_selection_callback_;
 
   UniqueAudioInputStreamFactoryPtr audio_input_stream_factory_;
-  UniqueAudioOutputStreamFactoryPtr audio_output_stream_factory_;
+
+  // We switch between |audio_service_audio_output_stream_factory_| and
+  // |in_content_audio_output_stream_factory_| based on
+  // features::kAudioServiceAudioStreams status.
+  base::Optional<RenderFrameAudioOutputStreamFactory>
+      audio_service_audio_output_stream_factory_;
+  UniqueAudioOutputStreamFactoryPtr in_content_audio_output_stream_factory_;
 
 #if BUILDFLAG(ENABLE_WEBRTC)
   std::unique_ptr<MediaStreamDispatcherHost, BrowserThread::DeleteOnIOThread>
diff --git a/content/browser/loader/mime_sniffing_resource_handler.cc b/content/browser/loader/mime_sniffing_resource_handler.cc
index 305f48e6..bed70ac 100644
--- a/content/browser/loader/mime_sniffing_resource_handler.cc
+++ b/content/browser/loader/mime_sniffing_resource_handler.cc
@@ -23,6 +23,7 @@
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/loader/resource_request_info_impl.h"
 #include "content/browser/loader/stream_resource_handler.h"
+#include "content/browser/web_package/signed_exchange_utils.h"
 #include "content/browser/web_package/web_package_request_handler.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/plugin_service.h"
@@ -41,6 +42,7 @@
 #include "services/network/loader_util.h"
 #include "services/network/public/cpp/resource_response.h"
 #include "third_party/blink/public/common/mime_util/mime_util.h"
+#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
 #include "url/origin.h"
 
 namespace content {
@@ -457,11 +459,10 @@
   if (!must_download) {
     if (blink::IsSupportedMimeType(mime_type))
       return true;
-    if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange) &&
-        WebPackageRequestHandler::IsSupportedMimeType(mime_type)) {
+    if (signed_exchange_utils::ShouldHandleAsSignedHTTPExchange(
+            request()->url(), response_->head)) {
       return true;
     }
-
     bool handled_by_plugin;
     if (!CheckForPluginHandler(&handled_by_plugin))
       return false;
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 87a1b0f..1f33bee8 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -34,6 +34,7 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/web_package/signed_exchange_consts.h"
 #include "content/browser/web_package/signed_exchange_url_loader_factory_for_non_network_service.h"
+#include "content/browser/web_package/signed_exchange_utils.h"
 #include "content/browser/web_package/web_package_request_handler.h"
 #include "content/browser/webui/url_data_manager_backend.h"
 #include "content/browser/webui/web_ui_url_loader_factory_internal.h"
@@ -80,10 +81,13 @@
     g_interceptor = LAZY_INSTANCE_INITIALIZER;
 
 // Returns true if interception by NavigationLoaderInterceptors is enabled.
+// Both ServiceWorkerServicification and SignedExchange require the loader
+// interception. So even if NetworkService is not enabled, returns true when one
+// of them is enabled.
 bool IsLoaderInterceptionEnabled() {
   return base::FeatureList::IsEnabled(network::features::kNetworkService) ||
-         base::FeatureList::IsEnabled(features::kSignedHTTPExchange) ||
-         ServiceWorkerUtils::IsServicificationEnabled();
+         ServiceWorkerUtils::IsServicificationEnabled() ||
+         signed_exchange_utils::IsSignedExchangeHandlingEnabled();
 }
 
 // Request ID for browser initiated requests. We start at -2 on the same lines
@@ -180,7 +184,10 @@
       request_info->begin_params->headers);
 
   std::string accept_value = network::kFrameAcceptHeader;
-  if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange)) {
+  // TODO(https://crbug.com/840704): Decide whether the Accept header should
+  // advertise the state of kSignedHTTPExchangeOriginTrial before starting the
+  // Origin-Trial.
+  if (signed_exchange_utils::IsSignedExchangeHandlingEnabled()) {
     DCHECK(!accept_value.empty());
     accept_value.append(kAcceptHeaderSignedExchangeSuffix);
   }
@@ -346,7 +353,7 @@
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
     default_loader_used_ = true;
-    if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange)) {
+    if (signed_exchange_utils::IsSignedExchangeHandlingEnabled()) {
       DCHECK(!default_url_loader_factory_getter_);
       // It is safe to pass the callback of CreateURLLoaderThrottles with the
       // unretained |this|, because the passed callback will be used by a
@@ -539,7 +546,7 @@
         interceptors_.push_back(std::move(appcache_interceptor));
     }
 
-    if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange)) {
+    if (signed_exchange_utils::IsSignedExchangeHandlingEnabled()) {
       // It is safe to pass the callback of CreateURLLoaderThrottles with the
       // unretained |this|, because the passed callback will be used by a
       // SignedExchangeHandler which is indirectly owned by |this| until its
@@ -1222,9 +1229,7 @@
     GetContentClient()
         ->browser()
         ->RegisterNonNetworkNavigationURLLoaderFactories(
-            frame_tree_node->current_frame_host()->GetProcess()->GetID(),
-            frame_tree_node->current_frame_host()->GetRoutingID(),
-            &non_network_url_loader_factories_);
+            frame_tree_node_id, &non_network_url_loader_factories_);
 
     // The embedder may want to proxy all network-bound URLLoaderFactory
     // requests that it can. If it elects to do so, we'll pass its proxy
diff --git a/content/browser/loader/prefetch_url_loader.cc b/content/browser/loader/prefetch_url_loader.cc
index cd7120f..225e39d 100644
--- a/content/browser/loader/prefetch_url_loader.cc
+++ b/content/browser/loader/prefetch_url_loader.cc
@@ -5,6 +5,7 @@
 #include "content/browser/loader/prefetch_url_loader.h"
 
 #include "base/feature_list.h"
+#include "content/browser/web_package/signed_exchange_utils.h"
 #include "content/browser/web_package/web_package_prefetch_handler.h"
 #include "content/public/common/content_features.h"
 #include "net/url_request/url_request_context_getter.h"
@@ -81,7 +82,7 @@
 void PrefetchURLLoader::OnReceiveResponse(
     const network::ResourceResponseHead& response,
     network::mojom::DownloadedTempFilePtr downloaded_file) {
-  if (WebPackagePrefetchHandler::IsResponseForWebPackage(response)) {
+  if (signed_exchange_utils::ShouldHandleAsSignedHTTPExchange(url_, response)) {
     DCHECK(!web_package_prefetch_handler_);
 
     // Note that after this point this doesn't directly get upcalls from the
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 3a2320c..9164766a 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -64,6 +64,7 @@
 #include "content/browser/streams/stream_context.h"
 #include "content/browser/streams/stream_registry.h"
 #include "content/browser/web_package/signed_exchange_consts.h"
+#include "content/browser/web_package/signed_exchange_utils.h"
 #include "content/common/net/url_request_service_worker_data.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/browser_child_process_host.h"
@@ -1626,7 +1627,10 @@
   headers.AddHeadersFromString(info.begin_params->headers);
 
   std::string accept_value = network::kFrameAcceptHeader;
-  if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange)) {
+  // TODO(https://crbug.com/840704): Decide whether the Accept header should
+  // advertise the state of kSignedHTTPExchangeOriginTrial before starting the
+  // Origin-Trial.
+  if (signed_exchange_utils::IsSignedExchangeHandlingEnabled()) {
     DCHECK(!accept_value.empty());
     accept_value.append(kAcceptHeaderSignedExchangeSuffix);
   }
diff --git a/content/browser/loader/resource_message_filter.cc b/content/browser/loader/resource_message_filter.cc
index 0cf44105..7118227d 100644
--- a/content/browser/loader/resource_message_filter.cc
+++ b/content/browser/loader/resource_message_filter.cc
@@ -14,6 +14,7 @@
 #include "content/browser/loader/resource_requester_info.h"
 #include "content/browser/loader/url_loader_factory_impl.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/web_package/signed_exchange_utils.h"
 #include "content/common/resource_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_context.h"
@@ -125,7 +126,7 @@
 
   // TODO(kinuko): Remove this flag guard when we have more confidence, this
   // doesn't need to be paired up with SignedExchange feature.
-  if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange) &&
+  if (signed_exchange_utils::IsSignedExchangeHandlingEnabled() &&
       url_request.resource_type == RESOURCE_TYPE_PREFETCH &&
       prefetch_url_loader_service_) {
     prefetch_url_loader_service_->CreateLoaderAndStart(
diff --git a/content/browser/loader/resource_requester_info.cc b/content/browser/loader/resource_requester_info.cc
index 9bde2f2..862ff7f 100644
--- a/content/browser/loader/resource_requester_info.cc
+++ b/content/browser/loader/resource_requester_info.cc
@@ -9,6 +9,7 @@
 #include "content/browser/appcache/chrome_appcache_service.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/web_package/signed_exchange_utils.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/child_process_host.h"
@@ -134,7 +135,7 @@
 ResourceRequesterInfo::CreateForCertificateFetcherForSignedExchange(
     const GetContextsCallback& get_contexts_callback) {
   DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
-  DCHECK(base::FeatureList::IsEnabled(features::kSignedHTTPExchange));
+  DCHECK(signed_exchange_utils::IsSignedExchangeHandlingEnabled());
   return scoped_refptr<ResourceRequesterInfo>(new ResourceRequesterInfo(
       RequesterType::CERTIFICATE_FETCHER_FOR_SIGNED_EXCHANGE,
       ChildProcessHost::kInvalidUniqueID, nullptr /* appcache_service */,
diff --git a/content/browser/media/audio_input_stream_broker.cc b/content/browser/media/audio_input_stream_broker.cc
index 8b5ae78..271dd39b 100644
--- a/content/browser/media/audio_input_stream_broker.cc
+++ b/content/browser/media/audio_input_stream_broker.cc
@@ -92,8 +92,8 @@
       browser_main_loop->keyboard_mic_registration()->Deregister();
   }
 #else
-  // Check that DisableKeyPressMonitoring() was called.
-  DCHECK(!user_input_monitor_);
+  if (user_input_monitor_)
+    user_input_monitor_->DisableKeyPressMonitoring();
 #endif
 
   auto* process_host = RenderProcessHost::FromID(render_process_id());
@@ -170,13 +170,6 @@
 
 void AudioInputStreamBroker::Cleanup() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (user_input_monitor_) {
-    user_input_monitor_->DisableKeyPressMonitoring();
-
-    // Set to nullptr to check that DisableKeyPressMonitoring() was called
-    // before destructor
-    user_input_monitor_ = nullptr;
-  }
 
   std::move(deleter_).Run(this);
 }
diff --git a/content/browser/media/audio_output_stream_broker.cc b/content/browser/media/audio_output_stream_broker.cc
index 72dab68..bacd6bc 100644
--- a/content/browser/media/audio_output_stream_broker.cc
+++ b/content/browser/media/audio_output_stream_broker.cc
@@ -102,12 +102,11 @@
     uint32_t reason,
     const std::string& description) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
-  if (reason ==
-      media::mojom::AudioOutputStreamObserver::kPlatformErrorDisconnectReason) {
-    client_.ResetWithReason(media::mojom::AudioOutputStreamProviderClient::
-                                kPlatformErrorDisconnectReason,
-                            std::string());
-  }
+  // TODO(https://crbug.com/787806): Don't propagate errors if we can retry
+  // instead.
+  client_.ResetWithReason(media::mojom::AudioOutputStreamProviderClient::
+                              kPlatformErrorDisconnectReason,
+                          std::string());
 
   Cleanup();
 }
diff --git a/content/browser/media/audio_output_stream_broker_unittest.cc b/content/browser/media/audio_output_stream_broker_unittest.cc
index 4b94dca..98fb2d4 100644
--- a/content/browser/media/audio_output_stream_broker_unittest.cc
+++ b/content/browser/media/audio_output_stream_broker_unittest.cc
@@ -258,7 +258,7 @@
 }
 
 TEST(AudioOutputStreamBrokerTest,
-     ObserverDisconnect_DoesNotPropagateErrorButCallsDeleter) {
+     ObserverDisconnect_PropagatesErrorAndCallsDeleter) {
   TestEnvironment env;
   MockStreamFactory::StreamRequestData stream_request_data(
       kDeviceId, TestParams(), env.group);
@@ -269,7 +269,9 @@
 
   EXPECT_TRUE(stream_request_data.requested);
   EXPECT_CALL(env.provider_client,
-              ConnectionError(/*general disconnect reason*/ 0, std::string()));
+              ConnectionError(media::mojom::AudioOutputStreamProviderClient::
+                                  kPlatformErrorDisconnectReason,
+                              std::string()));
   EXPECT_CALL(env.deleter, Run(env.broker.release()))
       .WillOnce(testing::DeleteArg<0>());
 
@@ -282,7 +284,7 @@
 }
 
 TEST(AudioOutputStreamBrokerTest,
-     FactoryDisconnectDuringConstruction_CallsDeleter) {
+     FactoryDisconnectDuringConstruction_PropagatesErrorAndCallsDeleter) {
   TestEnvironment env;
 
   env.broker->CreateStream(env.factory_ptr.get());
@@ -291,7 +293,9 @@
   EXPECT_CALL(env.deleter, Run(env.broker.release()))
       .WillOnce(testing::DeleteArg<0>());
   EXPECT_CALL(env.provider_client,
-              ConnectionError(/*general disconnect reason*/ 0, std::string()));
+              ConnectionError(media::mojom::AudioOutputStreamProviderClient::
+                                  kPlatformErrorDisconnectReason,
+                              std::string()));
 
   env.RunUntilIdle();
 }
diff --git a/content/browser/media/forwarding_audio_stream_factory.cc b/content/browser/media/forwarding_audio_stream_factory.cc
index 30edea5..ad71db9 100644
--- a/content/browser/media/forwarding_audio_stream_factory.cc
+++ b/content/browser/media/forwarding_audio_stream_factory.cc
@@ -38,6 +38,8 @@
 // static
 ForwardingAudioStreamFactory* ForwardingAudioStreamFactory::ForFrame(
     RenderFrameHost* frame) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
   auto* contents =
       static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(frame));
   if (!contents)
@@ -94,19 +96,10 @@
   CleanupStreamsBelongingTo(render_frame_host);
 }
 
-void ForwardingAudioStreamFactory::DidFinishNavigation(
-    NavigationHandle* navigation_handle) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (!navigation_handle->IsSameDocument()) {
-    // Document of frame will be destroyed, don't keep any streams around.
-    CleanupStreamsBelongingTo(navigation_handle->GetRenderFrameHost());
-  }
-}
-
 void ForwardingAudioStreamFactory::WebContentsDestroyed() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(inputs_.empty());
   DCHECK(outputs_.empty());
+  DCHECK(inputs_.empty());
 }
 
 void ForwardingAudioStreamFactory::CleanupStreamsBelongingTo(
@@ -121,8 +114,8 @@
            broker->render_frame_id() == frame_id;
   };
 
-  base::EraseIf(inputs_, match_rfh);
   base::EraseIf(outputs_, match_rfh);
+  base::EraseIf(inputs_, match_rfh);
 
   ResetRemoteFactoryPtrIfIdle();
 }
@@ -166,8 +159,8 @@
 void ForwardingAudioStreamFactory::ResetRemoteFactoryPtr() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   remote_factory_.reset();
-  inputs_.clear();
-  outputs_.clear();
+  // The stream brokers will call a callback to be deleted soon, give them a
+  // chance to signal an error to the client first.
 }
 
 }  // namespace content
diff --git a/content/browser/media/forwarding_audio_stream_factory.h b/content/browser/media/forwarding_audio_stream_factory.h
index ea0748aa..535a604e 100644
--- a/content/browser/media/forwarding_audio_stream_factory.h
+++ b/content/browser/media/forwarding_audio_stream_factory.h
@@ -68,11 +68,15 @@
       media::mojom::AudioOutputStreamProviderClientPtr client);
 
   // WebContentsObserver implementation. We observe these events so that we can
-  // clean up streams belonging to a document when that document is destroyed.
+  // clean up streams belonging to a frame when that frame is destroyed.
   void FrameDeleted(RenderFrameHost* render_frame_host) final;
-  void DidFinishNavigation(NavigationHandle* navigation_handle) final;
   void WebContentsDestroyed() final;
 
+  // E.g. to override binder.
+  service_manager::Connector* get_connector_for_testing() {
+    return connector_.get();
+  }
+
  private:
   using StreamBrokerSet = base::flat_set<std::unique_ptr<AudioStreamBroker>,
                                          base::UniquePtrComparator>;
diff --git a/content/browser/media/forwarding_audio_stream_factory_unittest.cc b/content/browser/media/forwarding_audio_stream_factory_unittest.cc
index 2d47c7d..b96e500 100644
--- a/content/browser/media/forwarding_audio_stream_factory_unittest.cc
+++ b/content/browser/media/forwarding_audio_stream_factory_unittest.cc
@@ -271,7 +271,7 @@
     testing::Mock::VerifyAndClear(&*other_rfh_broker);
   }
 
-  factory.FrameDeleted(other_rfh());
+  std::move(other_rfh_broker->deleter).Run(&*other_rfh_broker);
   EXPECT_FALSE(other_rfh_broker)
       << "Output broker should be destructed when deleter is called.";
   EXPECT_TRUE(main_rfh_broker);
@@ -367,39 +367,6 @@
          "WebContents is destructed.";
 }
 
-TEST_F(ForwardingAudioStreamFactoryTest, DestroyRemoteFactory_CleansUpStreams) {
-  mojom::RendererAudioInputStreamFactoryClientPtr input_client;
-  base::WeakPtr<MockBroker> input_broker =
-      ExpectInputBrokerConstruction(main_rfh());
-  media::mojom::AudioOutputStreamProviderClientPtr output_client;
-  base::WeakPtr<MockBroker> output_broker =
-      ExpectOutputBrokerConstruction(main_rfh());
-
-  ForwardingAudioStreamFactory factory(web_contents(), std::move(connector_),
-                                       std::move(broker_factory_));
-
-  EXPECT_CALL(*input_broker, CreateStream(NotNull()));
-  mojo::MakeRequest(&input_client);
-  factory.CreateInputStream(main_rfh(), kInputDeviceId, kParams,
-                            kSharedMemoryCount, kEnableAgc,
-                            std::move(input_client));
-
-  EXPECT_CALL(*output_broker, CreateStream(NotNull()));
-  mojo::MakeRequest(&output_client);
-  factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams,
-                             std::move(output_client));
-
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(input_broker);
-  EXPECT_TRUE(output_broker);
-  pending_factory_request_.reset();  // Triggers connection error.
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(input_broker) << "Input broker should be destructed when owning "
-                                "WebContents is destructed.";
-  EXPECT_FALSE(output_broker) << "Output broker should be destructed when "
-                                 "owning WebContents is destructed.";
-}
-
 TEST_F(ForwardingAudioStreamFactoryTest, LastStreamDeleted_ClearsFactoryPtr) {
   mojom::RendererAudioInputStreamFactoryClientPtr input_client;
   base::WeakPtr<MockBroker> main_rfh_input_broker =
diff --git a/content/browser/notifications/notification_event_dispatcher_impl.cc b/content/browser/notifications/notification_event_dispatcher_impl.cc
index fc707c86..1f00936 100644
--- a/content/browser/notifications/notification_event_dispatcher_impl.cc
+++ b/content/browser/notifications/notification_event_dispatcher_impl.cc
@@ -9,7 +9,6 @@
 #include "base/callback_helpers.h"
 #include "base/optional.h"
 #include "build/build_config.h"
-#include "content/browser/notifications/notification_message_filter.h"
 #include "content/browser/notifications/platform_notification_context_impl.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_registration.h"
diff --git a/content/browser/notifications/notification_message_filter.cc b/content/browser/notifications/notification_message_filter.cc
deleted file mode 100644
index 518fdf0..0000000
--- a/content/browser/notifications/notification_message_filter.cc
+++ /dev/null
@@ -1,326 +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 "content/browser/notifications/notification_message_filter.h"
-
-#include <utility>
-
-#include "base/callback.h"
-#include "base/command_line.h"
-#include "base/feature_list.h"
-#include "content/browser/bad_message.h"
-#include "content/browser/notifications/notification_event_dispatcher_impl.h"
-#include "content/browser/notifications/notification_id_generator.h"
-#include "content/browser/notifications/platform_notification_context_impl.h"
-#include "content/browser/service_worker/service_worker_context_wrapper.h"
-#include "content/common/platform_notification_messages.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/notification_database_data.h"
-#include "content/public/browser/platform_notification_service.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/common/content_client.h"
-#include "content/public/common/content_features.h"
-#include "content/public/common/content_switches.h"
-#include "third_party/blink/public/platform/modules/notifications/web_notification_constants.h"
-
-namespace content {
-
-namespace {
-
-const int kMinimumVibrationDurationMs = 1;      // 1 millisecond
-const int kMaximumVibrationDurationMs = 10000;  // 10 seconds
-
-PlatformNotificationData SanitizeNotificationData(
-    const PlatformNotificationData& notification_data) {
-  PlatformNotificationData sanitized_data = notification_data;
-
-  // Make sure that the vibration values are within reasonable bounds.
-  for (int& pattern : sanitized_data.vibration_pattern) {
-    pattern = std::min(kMaximumVibrationDurationMs,
-                       std::max(kMinimumVibrationDurationMs, pattern));
-  }
-
-  // Ensure there aren't more actions than supported.
-  if (sanitized_data.actions.size() > blink::kWebNotificationMaxActions)
-    sanitized_data.actions.resize(blink::kWebNotificationMaxActions);
-
-  return sanitized_data;
-}
-
-// Returns true when |resources| looks ok, false otherwise.
-bool ValidateNotificationResources(const NotificationResources& resources) {
-  if (!resources.image.drawsNothing() &&
-      !base::FeatureList::IsEnabled(features::kNotificationContentImage)) {
-    return false;
-  }
-  if (resources.image.width() > blink::kWebNotificationMaxImageWidthPx ||
-      resources.image.height() > blink::kWebNotificationMaxImageHeightPx) {
-    return false;
-  }
-  if (resources.notification_icon.width() >
-          blink::kWebNotificationMaxIconSizePx ||
-      resources.notification_icon.height() >
-          blink::kWebNotificationMaxIconSizePx) {
-    return false;
-  }
-  if (resources.badge.width() > blink::kWebNotificationMaxBadgeSizePx ||
-      resources.badge.height() > blink::kWebNotificationMaxBadgeSizePx) {
-    return false;
-  }
-  for (const auto& action_icon : resources.action_icons) {
-    if (action_icon.width() > blink::kWebNotificationMaxActionIconSizePx ||
-        action_icon.height() > blink::kWebNotificationMaxActionIconSizePx) {
-      return false;
-    }
-  }
-  return true;
-}
-
-}  // namespace
-
-NotificationMessageFilter::NotificationMessageFilter(
-    int process_id,
-    PlatformNotificationContextImpl* notification_context,
-    ResourceContext* resource_context,
-    const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
-    BrowserContext* browser_context)
-    : BrowserMessageFilter(PlatformNotificationMsgStart),
-      process_id_(process_id),
-      notification_context_(notification_context),
-      resource_context_(resource_context),
-      service_worker_context_(service_worker_context),
-      browser_context_(browser_context),
-      weak_factory_io_(this) {}
-
-NotificationMessageFilter::~NotificationMessageFilter() = default;
-
-void NotificationMessageFilter::OnDestruct() const {
-  BrowserThread::DeleteOnIOThread::Destruct(this);
-}
-
-bool NotificationMessageFilter::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(NotificationMessageFilter, message)
-    IPC_MESSAGE_HANDLER(PlatformNotificationHostMsg_ShowPersistent,
-                        OnShowPersistentNotification)
-    IPC_MESSAGE_HANDLER(PlatformNotificationHostMsg_GetNotifications,
-                        OnGetNotifications)
-    IPC_MESSAGE_HANDLER(PlatformNotificationHostMsg_ClosePersistent,
-                        OnClosePersistentNotification)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-
-  return handled;
-}
-
-void NotificationMessageFilter::OnShowPersistentNotification(
-    int request_id,
-    int64_t service_worker_registration_id,
-    const GURL& origin,
-    const PlatformNotificationData& notification_data,
-    const NotificationResources& notification_resources) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (GetPermissionForOriginOnIO(origin) !=
-      blink::mojom::PermissionStatus::GRANTED) {
-    // We can't assume that the renderer is compromised at this point because
-    // it's possible for the user to revoke an origin's permission between the
-    // time where a website requests the notification to be shown and the call
-    // arriving in the message filter.
-    return;
-  }
-
-  if (!ValidateNotificationResources(notification_resources)) {
-    bad_message::ReceivedBadMessage(this, bad_message::NMF_INVALID_ARGUMENT);
-    return;
-  }
-
-  NotificationDatabaseData database_data;
-  database_data.origin = origin;
-  database_data.service_worker_registration_id = service_worker_registration_id;
-
-  PlatformNotificationData sanitized_notification_data =
-      SanitizeNotificationData(notification_data);
-  database_data.notification_data = sanitized_notification_data;
-
-  notification_context_->WriteNotificationData(
-      origin, database_data,
-      base::Bind(&NotificationMessageFilter::DidWritePersistentNotificationData,
-                 weak_factory_io_.GetWeakPtr(), request_id,
-                 service_worker_registration_id, origin,
-                 sanitized_notification_data, notification_resources));
-}
-
-void NotificationMessageFilter::DidWritePersistentNotificationData(
-    int request_id,
-    int64_t service_worker_registration_id,
-    const GURL& origin,
-    const PlatformNotificationData& notification_data,
-    const NotificationResources& notification_resources,
-    bool success,
-    const std::string& notification_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  if (!success) {
-    Send(new PlatformNotificationMsg_DidShowPersistent(request_id, false));
-    return;
-  }
-
-  // Get the service worker scope.
-  service_worker_context_->FindReadyRegistrationForId(
-      service_worker_registration_id, origin,
-      base::BindOnce(
-          &NotificationMessageFilter::DidFindServiceWorkerRegistration,
-          weak_factory_io_.GetWeakPtr(), request_id, origin, notification_data,
-          notification_resources, notification_id));
-}
-
-void NotificationMessageFilter::DidFindServiceWorkerRegistration(
-    int request_id,
-    const GURL& origin,
-    const PlatformNotificationData& notification_data,
-    const NotificationResources& notification_resources,
-    const std::string& notification_id,
-    content::ServiceWorkerStatusCode service_worker_status,
-    scoped_refptr<content::ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  if (service_worker_status != SERVICE_WORKER_OK) {
-    Send(new PlatformNotificationMsg_DidShowPersistent(request_id, false));
-    LOG(ERROR) << "Registration not found for " << origin.spec();
-    // TODO(peter): Add UMA to track how often this occurs.
-    return;
-  }
-
-  PlatformNotificationService* service =
-      GetContentClient()->browser()->GetPlatformNotificationService();
-  DCHECK(service);
-
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::BindOnce(
-          &PlatformNotificationService::DisplayPersistentNotification,
-          base::Unretained(service),  // The service is a singleton.
-          browser_context_, notification_id, registration->pattern(), origin,
-          notification_data, notification_resources));
-
-  Send(new PlatformNotificationMsg_DidShowPersistent(request_id, true));
-}
-
-void NotificationMessageFilter::OnGetNotifications(
-    int request_id,
-    int64_t service_worker_registration_id,
-    const GURL& origin,
-    const std::string& filter_tag) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (GetPermissionForOriginOnIO(origin) !=
-      blink::mojom::PermissionStatus::GRANTED) {
-    // No permission has been granted for the given origin. It is harmless to
-    // try to get notifications without permission, so return an empty vector
-    // indicating that no (accessible) notifications exist at this time.
-    Send(new PlatformNotificationMsg_DidGetNotifications(
-        request_id, std::vector<PersistentNotificationInfo>()));
-    return;
-  }
-
-  notification_context_->ReadAllNotificationDataForServiceWorkerRegistration(
-      origin, service_worker_registration_id,
-      base::Bind(&NotificationMessageFilter::DidGetNotifications,
-                 weak_factory_io_.GetWeakPtr(), request_id, filter_tag));
-}
-
-void NotificationMessageFilter::DidGetNotifications(
-    int request_id,
-    const std::string& filter_tag,
-    bool success,
-    const std::vector<NotificationDatabaseData>& notifications) {
-  std::vector<PersistentNotificationInfo> persistent_notifications;
-  for (const NotificationDatabaseData& database_data : notifications) {
-    if (!filter_tag.empty()) {
-      const std::string& tag = database_data.notification_data.tag;
-      if (tag != filter_tag)
-        continue;
-    }
-
-    persistent_notifications.push_back(std::make_pair(
-        database_data.notification_id, database_data.notification_data));
-  }
-
-  Send(new PlatformNotificationMsg_DidGetNotifications(
-      request_id, persistent_notifications));
-}
-
-void NotificationMessageFilter::OnClosePersistentNotification(
-    const GURL& origin,
-    const std::string& tag,
-    const std::string& notification_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (GetPermissionForOriginOnIO(origin) !=
-      blink::mojom::PermissionStatus::GRANTED) {
-    return;
-  }
-
-  PlatformNotificationService* service =
-      GetContentClient()->browser()->GetPlatformNotificationService();
-  DCHECK(service);
-
-  // There's no point in waiting until the database data has been removed before
-  // closing the notification presented to the user. Post that task immediately.
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::BindOnce(&PlatformNotificationService::ClosePersistentNotification,
-                     base::Unretained(service),  // The service is a singleton.
-                     browser_context_, notification_id));
-
-  notification_context_->DeleteNotificationData(
-      notification_id, origin,
-      base::Bind(
-          &NotificationMessageFilter::DidDeletePersistentNotificationData,
-          weak_factory_io_.GetWeakPtr()));
-}
-
-void NotificationMessageFilter::DidDeletePersistentNotificationData(
-    bool success) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  // TODO(peter): Consider feeding back to the renderer that the notification
-  // has been closed.
-}
-
-blink::mojom::PermissionStatus
-NotificationMessageFilter::GetPermissionForOriginOnIO(
-    const GURL& origin) const {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  PlatformNotificationService* service =
-      GetContentClient()->browser()->GetPlatformNotificationService();
-  if (!service)
-    return blink::mojom::PermissionStatus::DENIED;
-
-  return service->CheckPermissionOnIOThread(resource_context_, origin,
-                                            process_id_);
-}
-
-bool NotificationMessageFilter::VerifyNotificationPermissionGranted(
-    PlatformNotificationService* service,
-    const GURL& origin) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  blink::mojom::PermissionStatus permission_status =
-      service->CheckPermissionOnUIThread(browser_context_, origin, process_id_);
-
-  // We can't assume that the renderer is compromised at this point because
-  // it's possible for the user to revoke an origin's permission between the
-  // time where a website requests the notification to be shown and the call
-  // arriving in the message filter.
-
-  return permission_status == blink::mojom::PermissionStatus::GRANTED;
-}
-
-NotificationIdGenerator* NotificationMessageFilter::GetNotificationIdGenerator()
-    const {
-  return notification_context_->notification_id_generator();
-}
-
-}  // namespace content
diff --git a/content/browser/notifications/notification_message_filter.h b/content/browser/notifications/notification_message_filter.h
deleted file mode 100644
index 948e0f1..0000000
--- a/content/browser/notifications/notification_message_filter.h
+++ /dev/null
@@ -1,133 +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 CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_MESSAGE_FILTER_H_
-#define CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_MESSAGE_FILTER_H_
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "content/common/service_worker/service_worker_status_code.h"
-#include "content/public/browser/browser_message_filter.h"
-#include "content/public/browser/notification_database_data.h"
-#include "third_party/blink/public/platform/modules/permissions/permission_status.mojom.h"
-
-class GURL;
-
-namespace content {
-
-class BrowserContext;
-class NotificationIdGenerator;
-struct NotificationResources;
-class PlatformNotificationContextImpl;
-struct PlatformNotificationData;
-class PlatformNotificationService;
-class ResourceContext;
-class ServiceWorkerContextWrapper;
-class ServiceWorkerRegistration;
-
-class NotificationMessageFilter : public BrowserMessageFilter {
- public:
-  NotificationMessageFilter(
-      int process_id,
-      PlatformNotificationContextImpl* notification_context,
-      ResourceContext* resource_context,
-      const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
-      BrowserContext* browser_context);
-
-  // BrowserMessageFilter implementation. Called on the UI thread.
-  void OnDestruct() const override;
-  bool OnMessageReceived(const IPC::Message& message) override;
-
- protected:
-  ~NotificationMessageFilter() override;
-
- private:
-  friend class base::DeleteHelper<NotificationMessageFilter>;
-  friend class BrowserThread;
-
-  void OnShowPersistentNotification(
-      int request_id,
-      int64_t service_worker_registration_id,
-      const GURL& origin,
-      const PlatformNotificationData& notification_data,
-      const NotificationResources& notification_resources);
-  void OnGetNotifications(int request_id,
-                          int64_t service_worker_registration_id,
-                          const GURL& origin,
-                          const std::string& filter_tag);
-  void OnClosePersistentNotification(const GURL& origin,
-                                     const std::string& tag,
-                                     const std::string& notification_id);
-
-  // Callback to be invoked by the notification context when the notification
-  // data for the persistent notification may have been written, as indicated by
-  // |success|. Will present the notification to the user when successful.
-  void DidWritePersistentNotificationData(
-      int request_id,
-      int64_t service_worker_registration_id,
-      const GURL& origin,
-      const PlatformNotificationData& notification_data,
-      const NotificationResources& notification_resources,
-      bool success,
-      const std::string& notification_id);
-
-  // Callback to be invoked by the service worker context when the service
-  // worker registration was retrieved. Will present the notification to the
-  // user when successful.
-  void DidFindServiceWorkerRegistration(
-      int request_id,
-      const GURL& origin,
-      const PlatformNotificationData& notification_data,
-      const NotificationResources& notification_resources,
-      const std::string& notification_id,
-      content::ServiceWorkerStatusCode service_worker_status,
-      scoped_refptr<ServiceWorkerRegistration> registration);
-
-  // Callback to be invoked when all notifications belonging to a Service Worker
-  // registration have been read from the database. The |success| argument
-  // indicates whether the data could be read successfully, whereas the actual
-  // notifications will be stored in |notifications|.
-  void DidGetNotifications(
-      int request_id,
-      const std::string& filter_tag,
-      bool success,
-      const std::vector<NotificationDatabaseData>& notifications);
-
-  // Callback to be invoked when the data associated with a persistent
-  // notification has been removed by the database, unless an error occurred,
-  // which will be indicated by |success|.
-  void DidDeletePersistentNotificationData(bool success);
-
-  // Returns the permission status for |origin|. Must only be used on the IO
-  // thread. If the PlatformNotificationService is unavailable, permission will
-  // assumed to be denied.
-  blink::mojom::PermissionStatus GetPermissionForOriginOnIO(
-      const GURL& origin) const;
-
-  // Verifies that Web Notification permission has been granted for |origin| in
-  // cases where the renderer shouldn't send messages if it weren't the case.
-  bool VerifyNotificationPermissionGranted(PlatformNotificationService* service,
-                                           const GURL& origin);
-
-  // Returns the NotificationIdGenerator instance owned by the context.
-  NotificationIdGenerator* GetNotificationIdGenerator() const;
-
-  int process_id_;
-  scoped_refptr<PlatformNotificationContextImpl> notification_context_;
-  ResourceContext* resource_context_;
-  scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
-  BrowserContext* browser_context_;
-
-  base::WeakPtrFactory<NotificationMessageFilter> weak_factory_io_;
-
-  DISALLOW_COPY_AND_ASSIGN(NotificationMessageFilter);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_MESSAGE_FILTER_H_
diff --git a/content/browser/permissions/permission_service_context.h b/content/browser/permissions/permission_service_context.h
index 6c0dda7..b53bdbb 100644
--- a/content/browser/permissions/permission_service_context.h
+++ b/content/browser/permissions/permission_service_context.h
@@ -49,6 +49,9 @@
   GURL GetEmbeddingOrigin() const;
 
   RenderFrameHost* render_frame_host() const;
+  RenderProcessHost* render_process_host() const {
+    return render_process_host_;
+  }
 
  private:
   class PermissionSubscription;
diff --git a/content/browser/permissions/permission_service_impl.cc b/content/browser/permissions/permission_service_impl.cc
index f6c0538..b04d566 100644
--- a/content/browser/permissions/permission_service_impl.cc
+++ b/content/browser/permissions/permission_service_impl.cc
@@ -10,6 +10,9 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "build/build_config.h"
+#include "content/browser/bad_message.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/permission_manager.h"
 #include "content/public/browser/permission_type.h"
@@ -24,44 +27,64 @@
 
 namespace {
 
-PermissionType PermissionDescriptorToPermissionType(
-    const PermissionDescriptorPtr& descriptor) {
+bool PermissionDescriptorToPermissionType(
+    const PermissionDescriptorPtr& descriptor,
+    PermissionType* permission_type) {
   switch (descriptor->name) {
     case PermissionName::GEOLOCATION:
-      return PermissionType::GEOLOCATION;
+      *permission_type = PermissionType::GEOLOCATION;
+      return true;
     case PermissionName::NOTIFICATIONS:
-      return PermissionType::NOTIFICATIONS;
+      *permission_type = PermissionType::NOTIFICATIONS;
+      return true;
     case PermissionName::MIDI: {
       if (descriptor->extension && descriptor->extension->is_midi() &&
           descriptor->extension->get_midi()->sysex) {
-        return PermissionType::MIDI_SYSEX;
+        *permission_type = PermissionType::MIDI_SYSEX;
+        return true;
       }
-      return PermissionType::MIDI;
+      *permission_type = PermissionType::MIDI;
+      return true;
     }
     case PermissionName::PROTECTED_MEDIA_IDENTIFIER:
-      return PermissionType::PROTECTED_MEDIA_IDENTIFIER;
+#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
+      *permission_type = PermissionType::PROTECTED_MEDIA_IDENTIFIER;
+      return true;
+#else
+      NOTIMPLEMENTED();
+      return false;
+#endif
     case PermissionName::DURABLE_STORAGE:
-      return PermissionType::DURABLE_STORAGE;
+      *permission_type = PermissionType::DURABLE_STORAGE;
+      return true;
     case PermissionName::AUDIO_CAPTURE:
-      return PermissionType::AUDIO_CAPTURE;
+      *permission_type = PermissionType::AUDIO_CAPTURE;
+      return true;
     case PermissionName::VIDEO_CAPTURE:
-      return PermissionType::VIDEO_CAPTURE;
+      *permission_type = PermissionType::VIDEO_CAPTURE;
+      return true;
     case PermissionName::BACKGROUND_SYNC:
-      return PermissionType::BACKGROUND_SYNC;
+      *permission_type = PermissionType::BACKGROUND_SYNC;
+      return true;
     case PermissionName::SENSORS:
-      return PermissionType::SENSORS;
+      *permission_type = PermissionType::SENSORS;
+      return true;
     case PermissionName::ACCESSIBILITY_EVENTS:
-      return PermissionType::ACCESSIBILITY_EVENTS;
+      *permission_type = PermissionType::ACCESSIBILITY_EVENTS;
+      return true;
     case PermissionName::CLIPBOARD_READ:
-      return PermissionType::CLIPBOARD_READ;
+      *permission_type = PermissionType::CLIPBOARD_READ;
+      return true;
     case PermissionName::CLIPBOARD_WRITE:
-      return PermissionType::CLIPBOARD_WRITE;
+      *permission_type = PermissionType::CLIPBOARD_WRITE;
+      return true;
     case PermissionName::PAYMENT_HANDLER:
-      return PermissionType::PAYMENT_HANDLER;
+      *permission_type = PermissionType::PAYMENT_HANDLER;
+      return true;
   }
 
   NOTREACHED();
-  return PermissionType::NUM;
+  return false;
 }
 
 // This function allows the usage of the the multiple request map with single
@@ -145,8 +168,12 @@
   }
 
   std::vector<PermissionType> types(permissions.size());
-  for (size_t i = 0; i < types.size(); ++i)
-    types[i] = PermissionDescriptorToPermissionType(permissions[i]);
+  for (size_t i = 0; i < types.size(); ++i) {
+    if (!PermissionDescriptorToPermissionType(permissions[i], &types[i])) {
+      ReceivedBadMessage();
+      return;
+    }
+  }
 
   std::unique_ptr<PendingRequest> pending_request =
       std::make_unique<PendingRequest>(types, std::move(callback));
@@ -182,8 +209,11 @@
 void PermissionServiceImpl::RevokePermission(
     PermissionDescriptorPtr permission,
     PermissionStatusCallback callback) {
-  PermissionType permission_type =
-      PermissionDescriptorToPermissionType(permission);
+  PermissionType permission_type;
+  if (!PermissionDescriptorToPermissionType(permission, &permission_type)) {
+    ReceivedBadMessage();
+    return;
+  }
   PermissionStatus status = GetPermissionStatusFromType(permission_type);
 
   // Resetting the permission should only be possible if the permission is
@@ -208,14 +238,23 @@
     last_known_status = current_status;
   }
 
-  context_->CreateSubscription(PermissionDescriptorToPermissionType(permission),
-                               origin_, std::move(observer));
+  PermissionType type;
+  if (!PermissionDescriptorToPermissionType(permission, &type)) {
+    ReceivedBadMessage();
+    return;
+  }
+
+  context_->CreateSubscription(type, origin_, std::move(observer));
 }
 
 PermissionStatus PermissionServiceImpl::GetPermissionStatus(
     const PermissionDescriptorPtr& permission) {
-  return GetPermissionStatusFromType(
-      PermissionDescriptorToPermissionType(permission));
+  PermissionType type;
+  if (!PermissionDescriptorToPermissionType(permission, &type)) {
+    ReceivedBadMessage();
+    return PermissionStatus::DENIED;
+  }
+  return GetPermissionStatusFromType(type);
 }
 
 PermissionStatus PermissionServiceImpl::GetPermissionStatusFromType(
@@ -254,4 +293,16 @@
       embedding_origin.is_empty() ? requesting_origin : embedding_origin);
 }
 
+void PermissionServiceImpl::ReceivedBadMessage() {
+  if (context_->render_frame_host()) {
+    bad_message::ReceivedBadMessage(
+        context_->render_frame_host()->GetProcess(),
+        bad_message::PERMISSION_SERVICE_BAD_PERMISSION_DESCRIPTOR);
+  } else {
+    bad_message::ReceivedBadMessage(
+        context_->render_process_host(),
+        bad_message::PERMISSION_SERVICE_BAD_PERMISSION_DESCRIPTOR);
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/permissions/permission_service_impl.h b/content/browser/permissions/permission_service_impl.h
index ae0e8a4..85359a8 100644
--- a/content/browser/permissions/permission_service_impl.h
+++ b/content/browser/permissions/permission_service_impl.h
@@ -67,6 +67,7 @@
   blink::mojom::PermissionStatus GetPermissionStatusFromType(
       PermissionType type);
   void ResetPermissionStatus(PermissionType type);
+  void ReceivedBadMessage();
 
   RequestsMap pending_requests_;
   // context_ owns |this|.
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.mm b/content/browser/renderer_host/browser_compositor_view_mac.mm
index 6c377879..7c67f21a 100644
--- a/content/browser/renderer_host/browser_compositor_view_mac.mm
+++ b/content/browser/renderer_host/browser_compositor_view_mac.mm
@@ -14,7 +14,6 @@
 #include "base/trace_event/trace_event.h"
 #include "components/viz/common/features.h"
 #include "content/browser/compositor/image_transport_factory.h"
-#include "content/browser/renderer_host/compositor_resize_lock.h"
 #include "content/browser/renderer_host/display_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/context_factory.h"
diff --git a/content/browser/renderer_host/compositor_resize_lock.cc b/content/browser/renderer_host/compositor_resize_lock.cc
deleted file mode 100644
index 7336dba0..0000000
--- a/content/browser/renderer_host/compositor_resize_lock.cc
+++ /dev/null
@@ -1,60 +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 "content/browser/renderer_host/compositor_resize_lock.h"
-
-#include "base/metrics/histogram_macros.h"
-#include "base/trace_event/trace_event.h"
-#include "content/public/browser/browser_thread.h"
-#include "ui/compositor/compositor.h"
-
-namespace content {
-
-CompositorResizeLock::CompositorResizeLock(CompositorResizeLockClient* client,
-                                           const gfx::Size& new_size)
-    : client_(client),
-      expected_size_(new_size),
-      acquisition_time_(base::TimeTicks::Now()) {
-  TRACE_EVENT_ASYNC_BEGIN2("ui", "CompositorResizeLock", this, "width",
-                           expected_size().width(), "height",
-                           expected_size().height());
-}
-
-CompositorResizeLock::~CompositorResizeLock() {
-  compositor_lock_ = nullptr;
-  if (client_)
-    client_->CompositorResizeLockEnded();
-
-  TRACE_EVENT_ASYNC_END2("ui", "CompositorResizeLock", this, "width",
-                         expected_size().width(), "height",
-                         expected_size().height());
-
-  UMA_HISTOGRAM_TIMES("UI.CompositorResizeLock.Duration",
-                      base::TimeTicks::Now() - acquisition_time_);
-
-  UMA_HISTOGRAM_BOOLEAN("UI.CompositorResizeLock.TimedOut", timed_out_);
-}
-
-bool CompositorResizeLock::Lock() {
-  if (unlocked_ || compositor_lock_)
-    return false;
-  compositor_lock_ = client_->GetCompositorLock(this);
-  return true;
-}
-
-void CompositorResizeLock::UnlockCompositor() {
-  unlocked_ = true;
-  compositor_lock_ = nullptr;
-}
-
-void CompositorResizeLock::CompositorLockTimedOut() {
-  timed_out_ = true;
-  UnlockCompositor();
-  if (client_) {
-    client_->CompositorResizeLockEnded();
-    client_ = nullptr;
-  }
-}
-
-}  // namespace content
diff --git a/content/browser/renderer_host/compositor_resize_lock.h b/content/browser/renderer_host/compositor_resize_lock.h
deleted file mode 100644
index 2303689..0000000
--- a/content/browser/renderer_host/compositor_resize_lock.h
+++ /dev/null
@@ -1,68 +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 CONTENT_BROWSER_RENDERER_HOST_COMPOSITOR_RESIZE_LOCK_H_
-#define CONTENT_BROWSER_RENDERER_HOST_COMPOSITOR_RESIZE_LOCK_H_
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "content/common/content_export.h"
-#include "ui/compositor/compositor_lock.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace content {
-
-class CompositorResizeLockClient {
- public:
-  virtual ~CompositorResizeLockClient() {}
-
-  // Creates and returns a CompositorLock for the CompositoResizeLock to
-  // hold.
-  virtual std::unique_ptr<ui::CompositorLock> GetCompositorLock(
-      ui::CompositorLockClient* client) = 0;
-
-  // Called when the CompositorResizeLock ends. This can happen
-  // before the CompositorResizeLock is destroyed if it times out.
-  virtual void CompositorResizeLockEnded() = 0;
-};
-
-// Used to prevent further resizes while a resize is pending.
-class CONTENT_EXPORT CompositorResizeLock : public ui::CompositorLockClient {
- public:
-  CompositorResizeLock(CompositorResizeLockClient* client,
-                       const gfx::Size& new_size);
-  ~CompositorResizeLock() override;
-
-  // Returns |true| if the call locks the compositor, or false if it was ever
-  // locked/unlocked.
-  bool Lock();
-
-  // Releases the lock on the compositor without releasing the whole resize
-  // lock. The client is not told about this. If called before locking, it will
-  // prevent locking from happening.
-  void UnlockCompositor();
-
-  bool timed_out() const { return timed_out_; }
-
-  const gfx::Size& expected_size() const { return expected_size_; }
-
- private:
-  // ui::CompositorLockClient implementation.
-  void CompositorLockTimedOut() override;
-
-  CompositorResizeLockClient* client_;
-  const gfx::Size expected_size_;
-  std::unique_ptr<ui::CompositorLock> compositor_lock_;
-  bool unlocked_ = false;
-  bool timed_out_ = false;
-  const base::TimeTicks acquisition_time_;
-
-  DISALLOW_COPY_AND_ASSIGN(CompositorResizeLock);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_RENDERER_HOST_COMPOSITOR_RESIZE_LOCK_AURA_H_
diff --git a/content/browser/renderer_host/compositor_resize_lock_unittest.cc b/content/browser/renderer_host/compositor_resize_lock_unittest.cc
deleted file mode 100644
index f4c42a1..0000000
--- a/content/browser/renderer_host/compositor_resize_lock_unittest.cc
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/renderer_host/compositor_resize_lock.h"
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/test/null_task_runner.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-namespace {
-
-class FakeCompositorResizeLockClient : public CompositorResizeLockClient,
-                                       public ui::CompositorLockManagerClient {
- public:
-  FakeCompositorResizeLockClient()
-      : lock_manager_(new base::NullTaskRunner(), this) {}
-  std::unique_ptr<ui::CompositorLock> GetCompositorLock(
-      ui::CompositorLockClient* client) override {
-    created_ = true;
-    return lock_manager_.GetCompositorLock(client, base::TimeDelta());
-  }
-
-  // CompositorResizeLockClient implementation.
-  void CompositorResizeLockEnded() override {
-    // This informs when the CompositorResizeLock ends for the client to
-    // release anything else it is holding.
-    ended_ = true;
-  }
-
-  // ui::CompositorLockManagerClient implementation.
-  void OnCompositorLockStateChanged(bool locked) override {
-    if (!locked) {
-      // This is where the ui::Compositor would be physically unlocked.
-      unlocked_ = true;
-    }
-  }
-
-  void CauseTimeout() { lock_manager_.TimeoutLocksForTesting(); }
-
-  bool created() const { return created_; }
-  bool unlocked() const { return unlocked_; }
-  bool ended() const { return ended_; }
-
- private:
-  bool created_ = false;
-  bool unlocked_ = false;
-  bool ended_ = false;
-  ui::CompositorLockManager lock_manager_;
-};
-
-TEST(CompositorResizeLockTest, EndWithoutLock) {
-  FakeCompositorResizeLockClient resize_client;
-  gfx::Size resize_to(10, 11);
-
-  {
-    CompositorResizeLock resize_lock(&resize_client, resize_to);
-    EXPECT_FALSE(resize_client.created());
-    EXPECT_FALSE(resize_client.unlocked());
-    EXPECT_FALSE(resize_client.ended());
-  }
-  // The compositor was never locked.
-  EXPECT_FALSE(resize_client.unlocked());
-  // The resize lock tells the client when it is destroyed.
-  EXPECT_TRUE(resize_client.ended());
-}
-
-TEST(CompositorResizeLockTest, EndAfterLock) {
-  FakeCompositorResizeLockClient resize_client;
-  gfx::Size resize_to(10, 11);
-
-  {
-    CompositorResizeLock resize_lock(&resize_client, resize_to);
-    EXPECT_FALSE(resize_client.created());
-    EXPECT_FALSE(resize_client.ended());
-
-    resize_lock.Lock();
-    EXPECT_TRUE(resize_client.created());
-    EXPECT_FALSE(resize_client.ended());
-  }
-  // The resize lock unlocks the compositor when it ends.
-  EXPECT_TRUE(resize_client.unlocked());
-  // The resize lock tells the client when it ends.
-  EXPECT_TRUE(resize_client.ended());
-}
-
-TEST(CompositorResizeLockTest, EndAfterUnlock) {
-  FakeCompositorResizeLockClient resize_client;
-  gfx::Size resize_to(10, 11);
-
-  {
-    CompositorResizeLock resize_lock(&resize_client, resize_to);
-    EXPECT_FALSE(resize_client.created());
-    EXPECT_FALSE(resize_client.ended());
-
-    resize_lock.Lock();
-    EXPECT_TRUE(resize_client.created());
-    EXPECT_FALSE(resize_client.ended());
-
-    // Unlocking the compositor but keeping the resize lock.
-    resize_lock.UnlockCompositor();
-    EXPECT_TRUE(resize_client.unlocked());
-    EXPECT_FALSE(resize_client.ended());
-  }
-  // The resize lock tells the client when it ends.
-  EXPECT_TRUE(resize_client.ended());
-}
-
-TEST(CompositorResizeLockTest, EndAfterTimeout) {
-  FakeCompositorResizeLockClient resize_client;
-  gfx::Size resize_to(10, 11);
-
-  {
-    CompositorResizeLock resize_lock(&resize_client, resize_to);
-    EXPECT_FALSE(resize_client.created());
-    EXPECT_FALSE(resize_client.ended());
-
-    resize_lock.Lock();
-    EXPECT_TRUE(resize_client.created());
-    EXPECT_FALSE(resize_client.ended());
-
-    // A timeout tells the client that the lock ended.
-    resize_client.CauseTimeout();
-    EXPECT_TRUE(resize_client.unlocked());
-    EXPECT_TRUE(resize_client.ended());
-  }
-}
-
-class CallbackClient : public FakeCompositorResizeLockClient {
- public:
-  CallbackClient() = default;
-
-  void CompositorResizeLockEnded() override {
-    std::move(resize_lock_ended_).Run();
-  }
-
-  void set_resize_lock_ended(base::OnceClosure c) {
-    resize_lock_ended_ = std::move(c);
-  }
-
- private:
-  base::OnceClosure resize_lock_ended_;
-};
-
-TEST(CompositorResizeLockTest, TimeoutSetBeforeClientTold) {
-  CallbackClient resize_client;
-  gfx::Size resize_to(10, 11);
-
-  {
-    CompositorResizeLock resize_lock(&resize_client, resize_to);
-    resize_lock.Lock();
-
-    // When the resize lock times out, it should report that before telling
-    // the client about that.
-    bool saw_resize_lock_end = false;
-    auto resize_lock_ended = [](CompositorResizeLock* resize_lock, bool* saw) {
-      EXPECT_TRUE(resize_lock->timed_out());
-      *saw = true;
-    };
-    resize_client.set_resize_lock_ended(
-        base::BindOnce(resize_lock_ended, &resize_lock, &saw_resize_lock_end));
-
-    // A timeout tells the client that the lock ended.
-    resize_client.CauseTimeout();
-    EXPECT_TRUE(saw_resize_lock_end);
-  }
-}
-
-}  // namespace
-}  // namespace content
diff --git a/content/browser/renderer_host/delegated_frame_host_client_aura.cc b/content/browser/renderer_host/delegated_frame_host_client_aura.cc
index ae82cc4..177dfe8 100644
--- a/content/browser/renderer_host/delegated_frame_host_client_aura.cc
+++ b/content/browser/renderer_host/delegated_frame_host_client_aura.cc
@@ -51,19 +51,6 @@
   render_widget_host_view_->OnFrameTokenChangedForView(frame_token);
 }
 
-std::unique_ptr<ui::CompositorLock>
-DelegatedFrameHostClientAura::GetCompositorLock(
-    ui::CompositorLockClient* client) {
-  auto* window_host = render_widget_host_view_->window_->GetHost();
-  return window_host->compositor()->GetCompositorLock(client);
-}
-
-void DelegatedFrameHostClientAura::CompositorResizeLockEnded() {
-  auto* window_host = render_widget_host_view_->window_->GetHost();
-  window_host->dispatcher()->ReleasePointerMoves();
-  render_widget_host_view_->host_->SynchronizeVisualProperties();
-}
-
 void DelegatedFrameHostClientAura::DidReceiveFirstFrameAfterNavigation() {
   render_widget_host_view_->host_->DidReceiveFirstFrameAfterNavigation();
 }
diff --git a/content/browser/renderer_host/delegated_frame_host_client_aura.h b/content/browser/renderer_host/delegated_frame_host_client_aura.h
index 9af64eb..9a7964d 100644
--- a/content/browser/renderer_host/delegated_frame_host_client_aura.h
+++ b/content/browser/renderer_host/delegated_frame_host_client_aura.h
@@ -6,7 +6,6 @@
 #define CONTENT_BROWSER_RENDERER_HOST_DELEGATED_FRAME_HOST_CLIENT_AURA_H_
 
 #include "base/macros.h"
-#include "content/browser/renderer_host/compositor_resize_lock.h"
 #include "content/browser/renderer_host/delegated_frame_host.h"
 #include "content/common/content_export.h"
 
@@ -16,8 +15,7 @@
 
 // DelegatedFrameHostClient implementation for aura, not used in mus.
 class CONTENT_EXPORT DelegatedFrameHostClientAura
-    : public DelegatedFrameHostClient,
-      public CompositorResizeLockClient {
+    : public DelegatedFrameHostClient {
  public:
   explicit DelegatedFrameHostClientAura(
       RenderWidgetHostViewAura* render_widget_host_view);
@@ -37,11 +35,6 @@
   void OnFrameTokenChanged(uint32_t frame_token) override;
   void DidReceiveFirstFrameAfterNavigation() override;
 
-  // CompositorResizeLockClient implementation.
-  std::unique_ptr<ui::CompositorLock> GetCompositorLock(
-      ui::CompositorLockClient* client) override;
-  void CompositorResizeLockEnded() override;
-
  private:
   RenderWidgetHostViewAura* render_widget_host_view_;
 
diff --git a/content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory.cc b/content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory.cc
new file mode 100644
index 0000000..df02e54
--- /dev/null
+++ b/content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory.cc
@@ -0,0 +1,140 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/task_runner_util.h"
+#include "content/browser/renderer_host/media/audio_output_authorization_handler.h"
+#include "content/browser/renderer_host/media/audio_output_stream_observer_impl.h"
+#include "content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h"
+#include "content/public/browser/render_frame_host.h"
+#include "media/base/audio_parameters.h"
+#include "media/mojo/services/mojo_audio_output_stream_provider.h"
+#include "mojo/public/cpp/bindings/message.h"
+
+namespace content {
+
+// static
+std::unique_ptr<RenderFrameAudioOutputStreamFactoryHandle,
+                BrowserThread::DeleteOnIOThread>
+RenderFrameAudioOutputStreamFactoryHandle::CreateFactory(
+    RendererAudioOutputStreamFactoryContext* context,
+    int render_frame_id,
+    mojom::RendererAudioOutputStreamFactoryRequest request) {
+  std::unique_ptr<RenderFrameAudioOutputStreamFactoryHandle,
+                  BrowserThread::DeleteOnIOThread>
+      handle(new RenderFrameAudioOutputStreamFactoryHandle(context,
+                                                           render_frame_id));
+  // Unretained is safe since |*handle| must be posted to the IO thread prior to
+  // deletion.
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&RenderFrameAudioOutputStreamFactoryHandle::Init,
+                     base::Unretained(handle.get()), std::move(request)));
+  return handle;
+}
+
+RenderFrameAudioOutputStreamFactoryHandle::
+    ~RenderFrameAudioOutputStreamFactoryHandle() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+}
+
+RenderFrameAudioOutputStreamFactoryHandle::
+    RenderFrameAudioOutputStreamFactoryHandle(
+        RendererAudioOutputStreamFactoryContext* context,
+        int render_frame_id)
+    : impl_(render_frame_id, context), binding_(&impl_) {}
+
+void RenderFrameAudioOutputStreamFactoryHandle::Init(
+    mojom::RendererAudioOutputStreamFactoryRequest request) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  binding_.Bind(std::move(request));
+}
+
+OldRenderFrameAudioOutputStreamFactory::OldRenderFrameAudioOutputStreamFactory(
+    int render_frame_id,
+    RendererAudioOutputStreamFactoryContext* context)
+    : render_frame_id_(render_frame_id),
+      context_(context),
+      weak_ptr_factory_(this) {
+  DCHECK(context_);
+}
+
+OldRenderFrameAudioOutputStreamFactory::
+    ~OldRenderFrameAudioOutputStreamFactory() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  UMA_HISTOGRAM_EXACT_LINEAR("Media.Audio.OutputStreamsCanceledByBrowser",
+                             stream_providers_.size(), 50);
+  // Make sure to close all streams.
+  stream_providers_.clear();
+}
+
+void OldRenderFrameAudioOutputStreamFactory::RequestDeviceAuthorization(
+    media::mojom::AudioOutputStreamProviderRequest stream_provider_request,
+    int32_t session_id,
+    const std::string& device_id,
+    RequestDeviceAuthorizationCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  const base::TimeTicks auth_start_time = base::TimeTicks::Now();
+
+  context_->RequestDeviceAuthorization(
+      render_frame_id_, session_id, device_id,
+      base::BindOnce(
+          &OldRenderFrameAudioOutputStreamFactory::AuthorizationCompleted,
+          weak_ptr_factory_.GetWeakPtr(), auth_start_time,
+          std::move(stream_provider_request), std::move(callback)));
+}
+
+void OldRenderFrameAudioOutputStreamFactory::AuthorizationCompleted(
+    base::TimeTicks auth_start_time,
+    media::mojom::AudioOutputStreamProviderRequest request,
+    RequestDeviceAuthorizationCallback callback,
+    media::OutputDeviceStatus status,
+    const media::AudioParameters& params,
+    const std::string& raw_device_id,
+    const std::string& device_id_for_renderer) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  AudioOutputAuthorizationHandler::UMALogDeviceAuthorizationTime(
+      auth_start_time);
+
+  if (status != media::OUTPUT_DEVICE_STATUS_OK) {
+    std::move(callback).Run(media::OutputDeviceStatus(status),
+                            media::AudioParameters::UnavailableDeviceParams(),
+                            std::string());
+    return;
+  }
+
+  int stream_id = next_stream_id_++;
+  std::unique_ptr<media::mojom::AudioOutputStreamObserver> observer =
+      std::make_unique<AudioOutputStreamObserverImpl>(
+          context_->GetRenderProcessId(), render_frame_id_, stream_id);
+  // Since |context_| outlives |this| and |this| outlives |stream_providers_|,
+  // unretained is safe.
+  stream_providers_.insert(
+      std::make_unique<media::MojoAudioOutputStreamProvider>(
+          std::move(request),
+          base::BindOnce(
+              &RendererAudioOutputStreamFactoryContext::CreateDelegate,
+              base::Unretained(context_), raw_device_id, render_frame_id_,
+              stream_id),
+          base::BindOnce(&OldRenderFrameAudioOutputStreamFactory::RemoveStream,
+                         base::Unretained(this)),
+          std::move(observer)));
+
+  std::move(callback).Run(media::OutputDeviceStatus(status), params,
+                          device_id_for_renderer);
+}
+
+void OldRenderFrameAudioOutputStreamFactory::RemoveStream(
+    media::mojom::AudioOutputStreamProvider* stream_provider) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  stream_providers_.erase(stream_provider);
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory.h b/content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory.h
new file mode 100644
index 0000000..f0d2413
--- /dev/null
+++ b/content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory.h
@@ -0,0 +1,109 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_OLD_RENDER_FRAME_AUDIO_OUTPUT_STREAM_FACTORY_H_
+#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_OLD_RENDER_FRAME_AUDIO_OUTPUT_STREAM_FACTORY_H_
+
+#include <memory>
+#include <string>
+
+#include "base/containers/flat_set.h"
+#include "base/containers/unique_ptr_adapters.h"
+#include "content/common/content_export.h"
+#include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
+#include "content/public/browser/browser_thread.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace content {
+
+class RendererAudioOutputStreamFactoryContext;
+
+// Handles a RendererAudioOutputStreamFactory request for a render frame host,
+// using the provided RendererAudioOutputStreamFactoryContext. This class may
+// be constructed on any thread, but must be used on the IO thread after that.
+// This class is used for creating streams hosted by the browser. It is being
+// replaced by RenderFrameAudioOutputStreamFactory, which forwards stream
+// requests to the audio service (https://crbug.com/830493).
+class CONTENT_EXPORT OldRenderFrameAudioOutputStreamFactory
+    : public mojom::RendererAudioOutputStreamFactory {
+ public:
+  OldRenderFrameAudioOutputStreamFactory(
+      int render_frame_id,
+      RendererAudioOutputStreamFactoryContext* context);
+
+  ~OldRenderFrameAudioOutputStreamFactory() override;
+
+ private:
+  using OutputStreamProviderSet =
+      base::flat_set<std::unique_ptr<media::mojom::AudioOutputStreamProvider>,
+                     base::UniquePtrComparator>;
+
+  // mojom::RendererAudioOutputStreamFactory implementation.
+  void RequestDeviceAuthorization(
+      media::mojom::AudioOutputStreamProviderRequest stream_provider,
+      int32_t session_id,
+      const std::string& device_id,
+      RequestDeviceAuthorizationCallback callback) override;
+
+  // Here, the |raw_device_id| is used to create the stream, and
+  // |device_id_for_renderer| is nonempty in the case when the renderer
+  // requested a device using a |session_id|, to let it know which device was
+  // chosen. This id is hashed.
+  void AuthorizationCompleted(
+      base::TimeTicks auth_start_time,
+      media::mojom::AudioOutputStreamProviderRequest request,
+      RequestDeviceAuthorizationCallback callback,
+      media::OutputDeviceStatus status,
+      const media::AudioParameters& params,
+      const std::string& raw_device_id,
+      const std::string& device_id_for_renderer);
+
+  void RemoveStream(media::mojom::AudioOutputStreamProvider* stream_provider);
+
+  const int render_frame_id_;
+  RendererAudioOutputStreamFactoryContext* const context_;
+
+  // The stream providers will contain the corresponding streams.
+  OutputStreamProviderSet stream_providers_;
+
+  // All streams require IDs. Use a counter to generate them.
+  int next_stream_id_ = 0;
+
+  base::WeakPtrFactory<OldRenderFrameAudioOutputStreamFactory>
+      weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(OldRenderFrameAudioOutputStreamFactory);
+};
+
+// This class is a convenient bundle of factory and binding.
+class CONTENT_EXPORT RenderFrameAudioOutputStreamFactoryHandle {
+ public:
+  static std::unique_ptr<RenderFrameAudioOutputStreamFactoryHandle,
+                         BrowserThread::DeleteOnIOThread>
+  CreateFactory(RendererAudioOutputStreamFactoryContext* context,
+                int render_frame_id,
+                mojom::RendererAudioOutputStreamFactoryRequest request);
+
+  ~RenderFrameAudioOutputStreamFactoryHandle();
+
+ private:
+  RenderFrameAudioOutputStreamFactoryHandle(
+      RendererAudioOutputStreamFactoryContext* context,
+      int render_frame_id);
+
+  void Init(mojom::RendererAudioOutputStreamFactoryRequest request);
+
+  OldRenderFrameAudioOutputStreamFactory impl_;
+  mojo::Binding<mojom::RendererAudioOutputStreamFactory> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderFrameAudioOutputStreamFactoryHandle);
+};
+
+using UniqueAudioOutputStreamFactoryPtr =
+    std::unique_ptr<RenderFrameAudioOutputStreamFactoryHandle,
+                    BrowserThread::DeleteOnIOThread>;
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_OLD_RENDER_FRAME_AUDIO_OUTPUT_STREAM_FACTORY_H_
diff --git a/content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory_unittest.cc b/content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory_unittest.cc
new file mode 100644
index 0000000..6b4244b3
--- /dev/null
+++ b/content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory_unittest.cc
@@ -0,0 +1,336 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory.h"
+
+#include <limits>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/memory/shared_memory.h"
+#include "base/memory/shared_memory_handle.h"
+#include "base/run_loop.h"
+#include "base/sync_socket.h"
+#include "content/browser/renderer_host/media/media_stream_manager.h"
+#include "content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h"
+#include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "media/base/audio_parameters.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+using testing::Test;
+using AudioOutputStreamFactory = mojom::RendererAudioOutputStreamFactory;
+using AudioOutputStreamFactoryPtr =
+    mojo::InterfacePtr<AudioOutputStreamFactory>;
+using AudioOutputStreamFactoryRequest =
+    mojo::InterfaceRequest<AudioOutputStreamFactory>;
+using AudioOutputStream = media::mojom::AudioOutputStream;
+using AudioOutputStreamPtr = mojo::InterfacePtr<AudioOutputStream>;
+using AudioOutputStreamRequest = mojo::InterfaceRequest<AudioOutputStream>;
+using AudioOutputStreamProviderClient =
+    media::mojom::AudioOutputStreamProviderClient;
+using AudioOutputStreamProviderClientPtr =
+    mojo::InterfacePtr<AudioOutputStreamProviderClient>;
+using AudioOutputStreamProviderClientRequest =
+    mojo::InterfaceRequest<AudioOutputStreamProviderClient>;
+using AudioOutputStreamProvider = media::mojom::AudioOutputStreamProvider;
+using AudioOutputStreamProviderPtr =
+    mojo::InterfacePtr<AudioOutputStreamProvider>;
+using AudioOutputStreamProviderRequest =
+    mojo::InterfaceRequest<AudioOutputStreamProvider>;
+
+const int kStreamId = 0;
+const int kNoSessionId = 0;
+const int kRenderProcessId = 42;
+const int kRenderFrameId = 24;
+const int kSampleFrequency = 44100;
+const int kSamplesPerBuffer = kSampleFrequency / 100;
+const char kSalt[] = "salt";
+
+media::AudioParameters GetTestAudioParameters() {
+  return media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+                                media::CHANNEL_LAYOUT_MONO, kSampleFrequency,
+                                kSamplesPerBuffer);
+}
+
+class MockAudioOutputDelegate : public media::AudioOutputDelegate {
+ public:
+  // |on_destruction| can be used to observe the destruction of the delegate.
+  explicit MockAudioOutputDelegate(
+      base::OnceClosure on_destruction = base::OnceClosure())
+      : on_destruction_(std::move(on_destruction)) {}
+
+  ~MockAudioOutputDelegate() override {
+    if (on_destruction_)
+      std::move(on_destruction_).Run();
+  }
+
+  MOCK_METHOD0(GetStreamId, int());
+  MOCK_METHOD0(OnPlayStream, void());
+  MOCK_METHOD0(OnPauseStream, void());
+  MOCK_METHOD1(OnSetVolume, void(double));
+
+ private:
+  base::OnceClosure on_destruction_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockAudioOutputDelegate);
+};
+
+class MockContext : public RendererAudioOutputStreamFactoryContext {
+ public:
+  explicit MockContext(bool auth_ok) : salt_(kSalt), auth_ok_(auth_ok) {}
+
+  ~MockContext() override { EXPECT_EQ(nullptr, delegate_); }
+
+  int GetRenderProcessId() const override { return kRenderProcessId; }
+
+  void RequestDeviceAuthorization(
+      int render_frame_id,
+      int session_id,
+      const std::string& device_id,
+      AuthorizationCompletedCallback cb) const override {
+    EXPECT_EQ(render_frame_id, kRenderFrameId);
+    EXPECT_EQ(session_id, 0);
+    if (auth_ok_) {
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE,
+          base::BindOnce(std::move(cb),
+                         media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+                         GetTestAudioParameters(), "default", std::string()));
+      return;
+    }
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(std::move(cb),
+                       media::OutputDeviceStatus::
+                           OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
+                       media::AudioParameters::UnavailableDeviceParams(),
+                       std::string(), std::string()));
+  }
+
+  // The event handler for the delegate will be stored at
+  // |*event_handler_location| when the delegate is created.
+  void PrepareDelegateForCreation(
+      std::unique_ptr<media::AudioOutputDelegate> delegate,
+      media::AudioOutputDelegate::EventHandler** event_handler_location) {
+    EXPECT_EQ(nullptr, delegate_);
+    EXPECT_EQ(nullptr, delegate_event_handler_location_);
+    delegate_ = std::move(delegate);
+    delegate_event_handler_location_ = event_handler_location;
+  }
+
+  std::unique_ptr<media::AudioOutputDelegate> CreateDelegate(
+      const std::string& unique_device_id,
+      int render_frame_id,
+      int stream_id,
+      const media::AudioParameters& params,
+      media::mojom::AudioOutputStreamObserverPtr stream_observer,
+      media::AudioOutputDelegate::EventHandler* handler) override {
+    EXPECT_NE(nullptr, delegate_);
+    EXPECT_NE(nullptr, delegate_event_handler_location_);
+    *delegate_event_handler_location_ = handler;
+    delegate_event_handler_location_ = nullptr;
+    return std::move(delegate_);
+  }
+
+  AudioOutputStreamFactoryPtr CreateFactory() {
+    DCHECK(!factory_);
+    AudioOutputStreamFactoryPtr ret;
+    factory_ = std::make_unique<OldRenderFrameAudioOutputStreamFactory>(
+        kRenderFrameId, this);
+    factory_binding_ = std::make_unique<
+        mojo::Binding<mojom::RendererAudioOutputStreamFactory>>(
+        factory_.get(), mojo::MakeRequest(&ret));
+    return ret;
+  }
+
+ private:
+  const std::string salt_;
+  const bool auth_ok_;
+  std::unique_ptr<OldRenderFrameAudioOutputStreamFactory> factory_;
+  std::unique_ptr<mojo::Binding<mojom::RendererAudioOutputStreamFactory>>
+      factory_binding_;
+  std::unique_ptr<media::AudioOutputDelegate> delegate_;
+  media::AudioOutputDelegate::EventHandler** delegate_event_handler_location_ =
+      nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(MockContext);
+};
+
+class MockClient : public AudioOutputStreamProviderClient {
+ public:
+  MockClient() : provider_client_binding_(this) {}
+  ~MockClient() override {}
+
+  AudioOutputStreamProviderClientPtr MakeProviderClientPtr() {
+    AudioOutputStreamProviderClientPtr p;
+    provider_client_binding_.Bind(mojo::MakeRequest(&p));
+    return p;
+  }
+
+  void Created(AudioOutputStreamPtr stream,
+               media::mojom::AudioDataPipePtr data_pipe) override {
+    was_called_ = true;
+    stream_ = std::move(stream);
+  }
+
+  bool was_called() { return was_called_; }
+
+  MOCK_METHOD0(OnError, void());
+
+ private:
+  mojo::Binding<AudioOutputStreamProviderClient> provider_client_binding_;
+  AudioOutputStreamPtr stream_;
+  bool was_called_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(MockClient);
+};
+
+void AuthCallback(media::OutputDeviceStatus* status_out,
+                  media::AudioParameters* params_out,
+                  std::string* id_out,
+                  media::OutputDeviceStatus status,
+                  const media::AudioParameters& params,
+                  const std::string& id) {
+  *status_out = status;
+  *params_out = params;
+  *id_out = id;
+}
+
+}  // namespace
+
+// This test authorizes and creates a stream, and checks that
+// 1. the ProviderClient callback is called with appropriate parameters.
+// 2. the AudioOutputDelegate is created.
+// 3. when the delegate calls OnStreamCreated, this is propagated to the client.
+TEST(OldRenderFrameAudioOutputStreamFactoryTest, CreateStream) {
+  content::TestBrowserThreadBundle thread_bundle;
+  AudioOutputStreamProviderPtr provider;
+  MockClient client;
+  media::AudioOutputDelegate::EventHandler* event_handler = nullptr;
+  auto factory_context = std::make_unique<MockContext>(true);
+  factory_context->PrepareDelegateForCreation(
+      std::make_unique<MockAudioOutputDelegate>(), &event_handler);
+  AudioOutputStreamFactoryPtr factory_ptr = factory_context->CreateFactory();
+
+  media::OutputDeviceStatus status;
+  media::AudioParameters params;
+  std::string id;
+  factory_ptr->RequestDeviceAuthorization(
+      mojo::MakeRequest(&provider), kNoSessionId, "default",
+      base::BindOnce(&AuthCallback, base::Unretained(&status),
+                     base::Unretained(&params), base::Unretained(&id)));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(status, media::OUTPUT_DEVICE_STATUS_OK);
+  EXPECT_EQ(params.AsHumanReadableString(),
+            GetTestAudioParameters().AsHumanReadableString());
+  EXPECT_TRUE(id.empty());
+
+  provider->Acquire(params, client.MakeProviderClientPtr());
+  base::RunLoop().RunUntilIdle();
+  ASSERT_NE(event_handler, nullptr);
+
+  base::SharedMemory shared_memory;
+  ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(100));
+
+  auto local = std::make_unique<base::CancelableSyncSocket>();
+  auto remote = std::make_unique<base::CancelableSyncSocket>();
+  ASSERT_TRUE(
+      base::CancelableSyncSocket::CreatePair(local.get(), remote.get()));
+  event_handler->OnStreamCreated(kStreamId, &shared_memory, std::move(remote));
+
+  base::RunLoop().RunUntilIdle();
+  // Make sure we got the callback from creating stream.
+  EXPECT_TRUE(client.was_called());
+}
+
+TEST(OldRenderFrameAudioOutputStreamFactoryTest, NotAuthorized_Denied) {
+  content::TestBrowserThreadBundle thread_bundle;
+  AudioOutputStreamProviderPtr output_provider;
+  auto factory_context = std::make_unique<MockContext>(false);
+  AudioOutputStreamFactoryPtr factory_ptr = factory_context->CreateFactory();
+
+  media::OutputDeviceStatus status;
+  media::AudioParameters params;
+  std::string id;
+  factory_ptr->RequestDeviceAuthorization(
+      mojo::MakeRequest(&output_provider), kNoSessionId, "default",
+      base::BindOnce(&AuthCallback, base::Unretained(&status),
+                     base::Unretained(&params), base::Unretained(&id)));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(status, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED);
+  EXPECT_TRUE(id.empty());
+}
+
+TEST(OldRenderFrameAudioOutputStreamFactoryTest,
+     ConnectionError_DeletesStream) {
+  content::TestBrowserThreadBundle thread_bundle;
+  AudioOutputStreamProviderPtr provider;
+  MockClient client;
+  bool delegate_is_destructed = false;
+  media::AudioOutputDelegate::EventHandler* event_handler = nullptr;
+  auto factory_context = std::make_unique<MockContext>(true);
+  factory_context->PrepareDelegateForCreation(
+      std::make_unique<MockAudioOutputDelegate>(
+          base::BindOnce([](bool* destructed) { *destructed = true; },
+                         &delegate_is_destructed)),
+      &event_handler);
+  AudioOutputStreamFactoryPtr factory_ptr = factory_context->CreateFactory();
+
+  factory_ptr->RequestDeviceAuthorization(
+      mojo::MakeRequest(&provider), kNoSessionId, "default",
+      base::BindOnce([](media::OutputDeviceStatus status,
+                        const media::AudioParameters& params,
+                        const std::string& id) {}));
+  base::RunLoop().RunUntilIdle();
+
+  provider->Acquire(GetTestAudioParameters(), client.MakeProviderClientPtr());
+  base::RunLoop().RunUntilIdle();
+  ASSERT_NE(event_handler, nullptr);
+  EXPECT_FALSE(delegate_is_destructed);
+  provider.reset();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(delegate_is_destructed);
+}
+
+TEST(OldRenderFrameAudioOutputStreamFactoryTest, DelegateError_DeletesStream) {
+  content::TestBrowserThreadBundle thread_bundle;
+  AudioOutputStreamProviderPtr provider;
+  MockClient client;
+  bool delegate_is_destructed = false;
+  media::AudioOutputDelegate::EventHandler* event_handler = nullptr;
+  auto factory_context = std::make_unique<MockContext>(true);
+  factory_context->PrepareDelegateForCreation(
+      std::make_unique<MockAudioOutputDelegate>(
+          base::BindOnce([](bool* destructed) { *destructed = true; },
+                         &delegate_is_destructed)),
+      &event_handler);
+  AudioOutputStreamFactoryPtr factory_ptr = factory_context->CreateFactory();
+
+  factory_ptr->RequestDeviceAuthorization(
+      mojo::MakeRequest(&provider), kNoSessionId, "default",
+      base::BindOnce([](media::OutputDeviceStatus status,
+                        const media::AudioParameters& params,
+                        const std::string& id) {}));
+  base::RunLoop().RunUntilIdle();
+
+  provider->Acquire(GetTestAudioParameters(), client.MakeProviderClientPtr());
+  base::RunLoop().RunUntilIdle();
+  ASSERT_NE(event_handler, nullptr);
+  EXPECT_FALSE(delegate_is_destructed);
+  event_handler->OnStreamError(kStreamId);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(delegate_is_destructed);
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
index 3f012c44..a454957 100644
--- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
+++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
@@ -1,95 +1,114 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h"
 
-#include <memory>
 #include <utility>
 
-#include "base/metrics/histogram_macros.h"
-#include "base/task_runner_util.h"
+#include "content/browser/media/forwarding_audio_stream_factory.h"
 #include "content/browser/renderer_host/media/audio_output_authorization_handler.h"
-#include "content/browser/renderer_host/media/audio_output_stream_observer_impl.h"
-#include "content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h"
 #include "content/public/browser/render_frame_host.h"
-#include "media/base/audio_parameters.h"
-#include "media/mojo/services/mojo_audio_output_stream_provider.h"
-#include "mojo/public/cpp/bindings/message.h"
+#include "content/public/browser/render_process_host.h"
+#include "media/base/bind_to_current_loop.h"
 
 namespace content {
 
-// static
-std::unique_ptr<RenderFrameAudioOutputStreamFactoryHandle,
-                BrowserThread::DeleteOnIOThread>
-RenderFrameAudioOutputStreamFactoryHandle::CreateFactory(
-    RendererAudioOutputStreamFactoryContext* context,
-    int render_frame_id,
-    mojom::RendererAudioOutputStreamFactoryRequest request) {
-  std::unique_ptr<RenderFrameAudioOutputStreamFactoryHandle,
-                  BrowserThread::DeleteOnIOThread>
-      handle(new RenderFrameAudioOutputStreamFactoryHandle(context,
-                                                           render_frame_id));
-  // Unretained is safe since |*handle| must be posted to the IO thread prior to
-  // deletion.
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::BindOnce(&RenderFrameAudioOutputStreamFactoryHandle::Init,
-                     base::Unretained(handle.get()), std::move(request)));
-  return handle;
-}
+// This class implements media::mojom::AudioOutputStreamProvider for a single
+// streams and cleans itself up (using the |owner| pointer) when done.
+class RenderFrameAudioOutputStreamFactory::ProviderImpl final
+    : public media::mojom::AudioOutputStreamProvider {
+ public:
+  ProviderImpl(media::mojom::AudioOutputStreamProviderRequest request,
+               RenderFrameAudioOutputStreamFactory* owner,
+               const std::string& device_id)
+      : owner_(owner),
+        device_id_(device_id),
+        binding_(this, std::move(request)) {
+    DCHECK(owner_);
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    // Unretained is safe since |this| owns |binding_|.
+    binding_.set_connection_error_handler(
+        base::BindOnce(&ProviderImpl::Done, base::Unretained(this)));
+  }
 
-RenderFrameAudioOutputStreamFactoryHandle::
-    ~RenderFrameAudioOutputStreamFactoryHandle() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-}
+  ~ProviderImpl() final { DCHECK_CURRENTLY_ON(BrowserThread::UI); }
 
-RenderFrameAudioOutputStreamFactoryHandle::
-    RenderFrameAudioOutputStreamFactoryHandle(
-        RendererAudioOutputStreamFactoryContext* context,
-        int render_frame_id)
-    : impl_(render_frame_id, context), binding_(&impl_) {}
+  void Acquire(
+      const media::AudioParameters& params,
+      media::mojom::AudioOutputStreamProviderClientPtr provider_client) final {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    RenderFrameHost* frame = owner_->frame_;
+    ForwardingAudioStreamFactory* factory =
+        ForwardingAudioStreamFactory::ForFrame(frame);
+    if (factory) {
+      // It's possible that |frame| has already been destroyed, in which case we
+      // don't need to create a stream. In this case, the renderer will get a
+      // connection error since |provider_client| is dropped.
+      factory->CreateOutputStream(frame, device_id_, params,
+                                  std::move(provider_client));
+    }
 
-void RenderFrameAudioOutputStreamFactoryHandle::Init(
-    mojom::RendererAudioOutputStreamFactoryRequest request) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  binding_.Bind(std::move(request));
-}
+    // Since the stream creation has been propagated, |this| is no longer
+    // needed.
+    Done();
+  }
+
+  void Done() { owner_->DeleteProvider(this); }
+
+ private:
+  RenderFrameAudioOutputStreamFactory* const owner_;
+  const std::string device_id_;
+
+  mojo::Binding<media::mojom::AudioOutputStreamProvider> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProviderImpl);
+};
 
 RenderFrameAudioOutputStreamFactory::RenderFrameAudioOutputStreamFactory(
-    int render_frame_id,
-    RendererAudioOutputStreamFactoryContext* context)
-    : render_frame_id_(render_frame_id),
-      context_(context),
+    RenderFrameHost* frame,
+    media::AudioSystem* audio_system,
+    MediaStreamManager* media_stream_manager,
+    mojom::RendererAudioOutputStreamFactoryRequest request)
+    : binding_(this, std::move(request)),
+      frame_(frame),
+      authorization_handler_(
+          new AudioOutputAuthorizationHandler(audio_system,
+                                              media_stream_manager,
+                                              frame_->GetProcess()->GetID())),
       weak_ptr_factory_(this) {
-  DCHECK(context_);
-  // No thread-hostile state has been initialized yet, so we don't have to bind
-  // to this specific thread.
-  thread_checker_.DetachFromThread();
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 RenderFrameAudioOutputStreamFactory::~RenderFrameAudioOutputStreamFactory() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  UMA_HISTOGRAM_EXACT_LINEAR("Media.Audio.OutputStreamsCanceledByBrowser",
-                             stream_providers_.size(), 50);
-  // Make sure to close all streams.
-  stream_providers_.clear();
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 void RenderFrameAudioOutputStreamFactory::RequestDeviceAuthorization(
-    media::mojom::AudioOutputStreamProviderRequest stream_provider_request,
+    media::mojom::AudioOutputStreamProviderRequest provider_request,
     int32_t session_id,
     const std::string& device_id,
     RequestDeviceAuthorizationCallback callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   const base::TimeTicks auth_start_time = base::TimeTicks::Now();
-
-  context_->RequestDeviceAuthorization(
-      render_frame_id_, session_id, device_id,
-      base::BindOnce(
+  // TODO(https://crbug.com/837625): This thread hopping is suboptimal since
+  // AudioOutputAuthorizationHandler was made to be used on the IO thread.
+  // Make AudioOutputAuthorizationHandler work on the UI thread instead.
+  AudioOutputAuthorizationHandler::AuthorizationCompletedCallback
+      completed_callback = media::BindToCurrentLoop(base::BindOnce(
           &RenderFrameAudioOutputStreamFactory::AuthorizationCompleted,
           weak_ptr_factory_.GetWeakPtr(), auth_start_time,
-          std::move(stream_provider_request), std::move(callback)));
+          std::move(provider_request), std::move(callback)));
+
+  // Unretained is safe since |authorization_handler_| is deleted on the IO
+  // thread.
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(
+          &AudioOutputAuthorizationHandler::RequestDeviceAuthorization,
+          base::Unretained(authorization_handler_.get()),
+          frame_->GetRoutingID(), session_id, device_id,
+          std::move(completed_callback)));
 }
 
 void RenderFrameAudioOutputStreamFactory::AuthorizationCompleted(
@@ -100,43 +119,25 @@
     const media::AudioParameters& params,
     const std::string& raw_device_id,
     const std::string& device_id_for_renderer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   AudioOutputAuthorizationHandler::UMALogDeviceAuthorizationTime(
       auth_start_time);
 
-  if (status != media::OUTPUT_DEVICE_STATUS_OK) {
-    std::move(callback).Run(media::OutputDeviceStatus(status),
-                            media::AudioParameters::UnavailableDeviceParams(),
-                            std::string());
-    return;
+  // If |status| is not OK, this call will be considered as an error signal by
+  // the renderer.
+  std::move(callback).Run(status, params, device_id_for_renderer);
+
+  if (status == media::OUTPUT_DEVICE_STATUS_OK) {
+    stream_providers_.insert(std::make_unique<ProviderImpl>(
+        std::move(request), this, std::move(raw_device_id)));
   }
-
-  int stream_id = next_stream_id_++;
-  std::unique_ptr<media::mojom::AudioOutputStreamObserver> observer =
-      std::make_unique<AudioOutputStreamObserverImpl>(
-          context_->GetRenderProcessId(), render_frame_id_, stream_id);
-  // Since |context_| outlives |this| and |this| outlives |stream_providers_|,
-  // unretained is safe.
-  stream_providers_.insert(
-      std::make_unique<media::MojoAudioOutputStreamProvider>(
-          std::move(request),
-          base::BindOnce(
-              &RendererAudioOutputStreamFactoryContext::CreateDelegate,
-              base::Unretained(context_), raw_device_id, render_frame_id_,
-              stream_id),
-          base::BindOnce(&RenderFrameAudioOutputStreamFactory::RemoveStream,
-                         base::Unretained(this)),
-          std::move(observer)));
-
-  std::move(callback).Run(media::OutputDeviceStatus(status), params,
-                          device_id_for_renderer);
 }
 
-void RenderFrameAudioOutputStreamFactory::RemoveStream(
+void RenderFrameAudioOutputStreamFactory::DeleteProvider(
     media::mojom::AudioOutputStreamProvider* stream_provider) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  stream_providers_.erase(stream_provider);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  size_t deleted = stream_providers_.erase(stream_provider);
+  DCHECK_EQ(1u, deleted);
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h
index 8f42b90..fbc229b 100644
--- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h
+++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2018 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.
 
@@ -10,36 +10,55 @@
 
 #include "base/containers/flat_set.h"
 #include "base/containers/unique_ptr_adapters.h"
-#include "base/threading/thread_checker.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
 #include "content/common/content_export.h"
 #include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
 #include "content/public/browser/browser_thread.h"
+#include "media/base/output_device_info.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
+namespace media {
+class AudioSystem;
+class AudioParameters;
+}  // namespace media
+
 namespace content {
 
-class RendererAudioOutputStreamFactoryContext;
+class AudioOutputAuthorizationHandler;
+class MediaStreamManager;
+class RenderFrameHost;
 
-// Handles a RendererAudioOutputStreamFactory request for a render frame host,
-// using the provided RendererAudioOutputStreamFactoryContext. This class may
-// be constructed on any thread, but must be used on the IO thread after that.
+// This class, which lives on the UI thread, takes care of stream requests from
+// a render frame. It verifies that the stream creation is allowed and then
+// forwards the request to the appropriate ForwardingAudioStreamFactory.
 class CONTENT_EXPORT RenderFrameAudioOutputStreamFactory
     : public mojom::RendererAudioOutputStreamFactory {
  public:
   RenderFrameAudioOutputStreamFactory(
-      int render_frame_id,
-      RendererAudioOutputStreamFactoryContext* context);
+      RenderFrameHost* frame,
+      media::AudioSystem* audio_system,
+      MediaStreamManager* media_stream_manager,
+      mojom::RendererAudioOutputStreamFactoryRequest request);
 
   ~RenderFrameAudioOutputStreamFactory() override;
 
+  size_t current_number_of_providers_for_testing() {
+    return stream_providers_.size();
+  }
+
  private:
+  class ProviderImpl;
+  friend class ProviderImpl;  // For DeleteProvider.
+
   using OutputStreamProviderSet =
       base::flat_set<std::unique_ptr<media::mojom::AudioOutputStreamProvider>,
                      base::UniquePtrComparator>;
 
   // mojom::RendererAudioOutputStreamFactory implementation.
   void RequestDeviceAuthorization(
-      media::mojom::AudioOutputStreamProviderRequest stream_provider,
+      media::mojom::AudioOutputStreamProviderRequest provider_request,
       int32_t session_id,
       const std::string& device_id,
       RequestDeviceAuthorizationCallback callback) override;
@@ -57,51 +76,26 @@
       const std::string& raw_device_id,
       const std::string& device_id_for_renderer);
 
-  void RemoveStream(media::mojom::AudioOutputStreamProvider* stream_provider);
+  void DeleteProvider(media::mojom::AudioOutputStreamProvider* stream_provider);
 
-  const int render_frame_id_;
-  RendererAudioOutputStreamFactoryContext* const context_;
-  base::ThreadChecker thread_checker_;
+  const mojo::Binding<mojom::RendererAudioOutputStreamFactory> binding_;
+  RenderFrameHost* const frame_;
+  const std::unique_ptr<AudioOutputAuthorizationHandler,
+                        BrowserThread::DeleteOnIOThread>
+      authorization_handler_;
 
-  // The stream providers will contain the corresponding streams.
+  // The OutputStreamProviders for authorized streams are kept here while
+  // waiting for the renderer to finish creating the stream, and destructed
+  // afterwards.
   OutputStreamProviderSet stream_providers_;
 
-  // All streams require IDs. Use a counter to generate them.
-  int next_stream_id_ = 0;
-
+  // Weak pointers are used to cancel device authorizations that are in flight
+  // while |this| is destructed.
   base::WeakPtrFactory<RenderFrameAudioOutputStreamFactory> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderFrameAudioOutputStreamFactory);
 };
 
-// This class is a convenient bundle of factory and binding.
-class CONTENT_EXPORT RenderFrameAudioOutputStreamFactoryHandle {
- public:
-  static std::unique_ptr<RenderFrameAudioOutputStreamFactoryHandle,
-                         BrowserThread::DeleteOnIOThread>
-  CreateFactory(RendererAudioOutputStreamFactoryContext* context,
-                int render_frame_id,
-                mojom::RendererAudioOutputStreamFactoryRequest request);
-
-  ~RenderFrameAudioOutputStreamFactoryHandle();
-
- private:
-  RenderFrameAudioOutputStreamFactoryHandle(
-      RendererAudioOutputStreamFactoryContext* context,
-      int render_frame_id);
-
-  void Init(mojom::RendererAudioOutputStreamFactoryRequest request);
-
-  RenderFrameAudioOutputStreamFactory impl_;
-  mojo::Binding<mojom::RendererAudioOutputStreamFactory> binding_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenderFrameAudioOutputStreamFactoryHandle);
-};
-
-using UniqueAudioOutputStreamFactoryPtr =
-    std::unique_ptr<RenderFrameAudioOutputStreamFactoryHandle,
-                    BrowserThread::DeleteOnIOThread>;
-
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_RENDER_FRAME_AUDIO_OUTPUT_STREAM_FACTORY_H_
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
index 6d8e16e..837204a 100644
--- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
+++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
@@ -1,335 +1,262 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h"
 
-#include <limits>
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
-#include "base/memory/shared_memory.h"
-#include "base/memory/shared_memory_handle.h"
+#include "base/bind_helpers.h"
+#include "base/macros.h"
 #include "base/run_loop.h"
-#include "base/sync_socket.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/unguessable_token.h"
+#include "content/browser/media/forwarding_audio_stream_factory.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
-#include "content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h"
-#include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_browser_context.h"
-#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/test_renderer_host.h"
+#include "content/public/test/test_service_manager_context.h"
+#include "media/audio/audio_system_impl.h"
+#include "media/audio/fake_audio_log_factory.h"
+#include "media/audio/fake_audio_manager.h"
+#include "media/audio/test_audio_thread.h"
 #include "media/base/audio_parameters.h"
+#include "media/mojo/interfaces/audio_output_stream.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/system/platform_handle.h"
+#include "mojo/public/cpp/bindings/interface_request.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"
+#include "services/service_manager/public/cpp/connector.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using ::testing::_;
+using ::testing::Test;
+using ::testing::Mock;
+using ::testing::Ne;
+using ::testing::StrictMock;
+
 namespace content {
 
-namespace {
-
-using testing::Test;
-using AudioOutputStreamFactory = mojom::RendererAudioOutputStreamFactory;
-using AudioOutputStreamFactoryPtr =
-    mojo::InterfacePtr<AudioOutputStreamFactory>;
-using AudioOutputStreamFactoryRequest =
-    mojo::InterfaceRequest<AudioOutputStreamFactory>;
-using AudioOutputStream = media::mojom::AudioOutputStream;
-using AudioOutputStreamPtr = mojo::InterfacePtr<AudioOutputStream>;
-using AudioOutputStreamRequest = mojo::InterfaceRequest<AudioOutputStream>;
-using AudioOutputStreamProviderClient =
-    media::mojom::AudioOutputStreamProviderClient;
-using AudioOutputStreamProviderClientPtr =
-    mojo::InterfacePtr<AudioOutputStreamProviderClient>;
-using AudioOutputStreamProviderClientRequest =
-    mojo::InterfaceRequest<AudioOutputStreamProviderClient>;
-using AudioOutputStreamProvider = media::mojom::AudioOutputStreamProvider;
-using AudioOutputStreamProviderPtr =
-    mojo::InterfacePtr<AudioOutputStreamProvider>;
-using AudioOutputStreamProviderRequest =
-    mojo::InterfaceRequest<AudioOutputStreamProvider>;
-
-const int kStreamId = 0;
-const int kNoSessionId = 0;
-const int kRenderProcessId = 42;
-const int kRenderFrameId = 24;
-const int kSampleFrequency = 44100;
-const int kSamplesPerBuffer = kSampleFrequency / 100;
-const char kSalt[] = "salt";
-
-media::AudioParameters GetTestAudioParameters() {
-  return media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-                                media::CHANNEL_LAYOUT_MONO, kSampleFrequency,
-                                kSamplesPerBuffer);
-}
-
-class MockAudioOutputDelegate : public media::AudioOutputDelegate {
+class RenderFrameAudioOutputStreamFactoryTest
+    : public RenderViewHostTestHarness {
  public:
-  // |on_destruction| can be used to observe the destruction of the delegate.
-  explicit MockAudioOutputDelegate(
-      base::OnceClosure on_destruction = base::OnceClosure())
-      : on_destruction_(std::move(on_destruction)) {}
+  RenderFrameAudioOutputStreamFactoryTest()
+      : test_service_manager_context_(
+            std::make_unique<TestServiceManagerContext>()),
+        audio_manager_(std::make_unique<media::TestAudioThread>(),
+                       &log_factory_),
+        audio_system_(media::AudioSystemImpl::CreateInstance()),
+        media_stream_manager_(std::make_unique<MediaStreamManager>(
+            audio_system_.get(),
+            BrowserThread::GetTaskRunnerForThread(BrowserThread::UI))) {}
 
-  ~MockAudioOutputDelegate() override {
-    if (on_destruction_)
-      std::move(on_destruction_).Run();
+  ~RenderFrameAudioOutputStreamFactoryTest() override {}
+
+  void SetUp() override {
+    RenderViewHostTestHarness::SetUp();
+    RenderFrameHostTester::For(main_rfh())->InitializeRenderFrameIfNeeded();
+
+    // Set up the ForwardingAudioStreamFactory.
+    service_manager::Connector::TestApi connector_test_api(
+        ForwardingAudioStreamFactory::ForFrame(main_rfh())
+            ->get_connector_for_testing());
+    connector_test_api.OverrideBinderForTesting(
+        service_manager::Identity(audio::mojom::kServiceName),
+        audio::mojom::StreamFactory::Name_,
+        base::BindRepeating(
+            &RenderFrameAudioOutputStreamFactoryTest::BindFactory,
+            base::Unretained(this)));
+
+    base::RunLoop().RunUntilIdle();
   }
 
-  MOCK_METHOD0(GetStreamId, int());
-  MOCK_METHOD0(OnPlayStream, void());
-  MOCK_METHOD0(OnPauseStream, void());
-  MOCK_METHOD1(OnSetVolume, void(double));
+  void TearDown() override {
+    audio_manager_.Shutdown();
+    test_service_manager_context_.reset();
+    RenderViewHostTestHarness::TearDown();
+  }
 
- private:
-  base::OnceClosure on_destruction_;
+  void BindFactory(mojo::ScopedMessagePipeHandle factory_request) {
+    audio_service_stream_factory_.binding_.Bind(
+        audio::mojom::StreamFactoryRequest(std::move(factory_request)));
+  }
 
-  DISALLOW_COPY_AND_ASSIGN(MockAudioOutputDelegate);
-};
+  class MockStreamFactory : public audio::FakeStreamFactory {
+   public:
+    MockStreamFactory() {}
+    ~MockStreamFactory() override {}
 
-class MockContext : public RendererAudioOutputStreamFactoryContext {
- public:
-  explicit MockContext(bool auth_ok) : salt_(kSalt), auth_ok_(auth_ok) {}
-
-  ~MockContext() override { EXPECT_EQ(nullptr, delegate_); }
-
-  int GetRenderProcessId() const override { return kRenderProcessId; }
-
-  void RequestDeviceAuthorization(
-      int render_frame_id,
-      int session_id,
-      const std::string& device_id,
-      AuthorizationCompletedCallback cb) const override {
-    EXPECT_EQ(render_frame_id, kRenderFrameId);
-    EXPECT_EQ(session_id, 0);
-    if (auth_ok_) {
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE,
-          base::BindOnce(std::move(cb),
-                         media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
-                         GetTestAudioParameters(), "default", std::string()));
-      return;
+    void CreateOutputStream(
+        media::mojom::AudioOutputStreamRequest stream_request,
+        media::mojom::AudioOutputStreamObserverAssociatedPtrInfo observer_info,
+        media::mojom::AudioLogPtr log,
+        const std::string& output_device_id,
+        const media::AudioParameters& params,
+        const base::UnguessableToken& group_id,
+        CreateOutputStreamCallback created_callback) override {
+      last_created_callback = std::move(created_callback);
     }
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(std::move(cb),
-                       media::OutputDeviceStatus::
-                           OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
-                       media::AudioParameters::UnavailableDeviceParams(),
-                       std::string(), std::string()));
-  }
 
-  // The event handler for the delegate will be stored at
-  // |*event_handler_location| when the delegate is created.
-  void PrepareDelegateForCreation(
-      std::unique_ptr<media::AudioOutputDelegate> delegate,
-      media::AudioOutputDelegate::EventHandler** event_handler_location) {
-    EXPECT_EQ(nullptr, delegate_);
-    EXPECT_EQ(nullptr, delegate_event_handler_location_);
-    delegate_ = std::move(delegate);
-    delegate_event_handler_location_ = event_handler_location;
-  }
+    CreateOutputStreamCallback last_created_callback;
+  };
 
-  std::unique_ptr<media::AudioOutputDelegate> CreateDelegate(
-      const std::string& unique_device_id,
-      int render_frame_id,
-      int stream_id,
-      const media::AudioParameters& params,
-      media::mojom::AudioOutputStreamObserverPtr stream_observer,
-      media::AudioOutputDelegate::EventHandler* handler) override {
-    EXPECT_NE(nullptr, delegate_);
-    EXPECT_NE(nullptr, delegate_event_handler_location_);
-    *delegate_event_handler_location_ = handler;
-    delegate_event_handler_location_ = nullptr;
-    return std::move(delegate_);
-  }
+  using MockAuthorizationCallback = StrictMock<
+      base::MockCallback<base::OnceCallback<void(media::OutputDeviceStatus,
+                                                 const media::AudioParameters&,
+                                                 const std::string&)>>>;
 
-  AudioOutputStreamFactoryPtr CreateFactory() {
-    DCHECK(!factory_);
-    AudioOutputStreamFactoryPtr ret;
-    factory_ = std::make_unique<RenderFrameAudioOutputStreamFactory>(
-        kRenderFrameId, this);
-    factory_binding_ = std::make_unique<
-        mojo::Binding<mojom::RendererAudioOutputStreamFactory>>(
-        factory_.get(), mojo::MakeRequest(&ret));
-    return ret;
-  }
-
- private:
-  const std::string salt_;
-  const bool auth_ok_;
-  std::unique_ptr<RenderFrameAudioOutputStreamFactory> factory_;
-  std::unique_ptr<mojo::Binding<mojom::RendererAudioOutputStreamFactory>>
-      factory_binding_;
-  std::unique_ptr<media::AudioOutputDelegate> delegate_;
-  media::AudioOutputDelegate::EventHandler** delegate_event_handler_location_ =
-      nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(MockContext);
+  const char* kDefaultDeviceId = "default";
+  const char* kDeviceId =
+      "111122223333444455556666777788889999aaaabbbbccccddddeeeeffff";
+  const media::AudioParameters kParams =
+      media::AudioParameters::UnavailableDeviceParams();
+  const int kNoSessionId = 0;
+  MockStreamFactory audio_service_stream_factory_;
+  std::unique_ptr<TestServiceManagerContext> test_service_manager_context_;
+  media::FakeAudioLogFactory log_factory_;
+  media::FakeAudioManager audio_manager_;
+  std::unique_ptr<media::AudioSystem> audio_system_;
+  std::unique_ptr<MediaStreamManager> media_stream_manager_;
 };
 
-class MockClient : public AudioOutputStreamProviderClient {
- public:
-  MockClient() : provider_client_binding_(this) {}
-  ~MockClient() override {}
+TEST_F(RenderFrameAudioOutputStreamFactoryTest, ConstructDestruct) {
+  mojom::RendererAudioOutputStreamFactoryPtr factory_ptr;
+  RenderFrameAudioOutputStreamFactory factory(main_rfh(), audio_system_.get(),
+                                              media_stream_manager_.get(),
+                                              mojo::MakeRequest(&factory_ptr));
+}
 
-  AudioOutputStreamProviderClientPtr MakeProviderClientPtr() {
-    AudioOutputStreamProviderClientPtr p;
-    provider_client_binding_.Bind(mojo::MakeRequest(&p));
-    return p;
+TEST_F(RenderFrameAudioOutputStreamFactoryTest,
+       RequestDeviceAuthorizationForDefaultDevice_StatusOk) {
+  mojom::RendererAudioOutputStreamFactoryPtr factory_ptr;
+  RenderFrameAudioOutputStreamFactory factory(main_rfh(), audio_system_.get(),
+                                              media_stream_manager_.get(),
+                                              mojo::MakeRequest(&factory_ptr));
+
+  media::mojom::AudioOutputStreamProviderPtr provider_ptr;
+  MockAuthorizationCallback mock_callback;
+  factory_ptr->RequestDeviceAuthorization(mojo::MakeRequest(&provider_ptr),
+                                          kNoSessionId, kDefaultDeviceId,
+                                          mock_callback.Get());
+
+  EXPECT_CALL(mock_callback,
+              Run(media::OUTPUT_DEVICE_STATUS_OK, _, std::string()));
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(1u, factory.current_number_of_providers_for_testing());
+}
+
+TEST_F(
+    RenderFrameAudioOutputStreamFactoryTest,
+    RequestDeviceAuthorizationForDefaultDeviceAndDestroyProviderPtr_CleansUp) {
+  mojom::RendererAudioOutputStreamFactoryPtr factory_ptr;
+  RenderFrameAudioOutputStreamFactory factory(main_rfh(), audio_system_.get(),
+                                              media_stream_manager_.get(),
+                                              mojo::MakeRequest(&factory_ptr));
+
+  media::mojom::AudioOutputStreamProviderPtr provider_ptr;
+  MockAuthorizationCallback mock_callback;
+  factory_ptr->RequestDeviceAuthorization(mojo::MakeRequest(&provider_ptr),
+                                          kNoSessionId, kDefaultDeviceId,
+                                          mock_callback.Get());
+  provider_ptr.reset();
+
+  EXPECT_CALL(mock_callback,
+              Run(media::OUTPUT_DEVICE_STATUS_OK, _, std::string()));
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(0u, factory.current_number_of_providers_for_testing());
+}
+
+TEST_F(
+    RenderFrameAudioOutputStreamFactoryTest,
+    RequestDeviceAuthorizationForNondefaultDeviceWithoutAuthorization_Fails) {
+  mojom::RendererAudioOutputStreamFactoryPtr factory_ptr;
+  RenderFrameAudioOutputStreamFactory factory(main_rfh(), audio_system_.get(),
+                                              media_stream_manager_.get(),
+                                              mojo::MakeRequest(&factory_ptr));
+
+  media::mojom::AudioOutputStreamProviderPtr provider_ptr;
+  MockAuthorizationCallback mock_callback;
+  factory_ptr->RequestDeviceAuthorization(mojo::MakeRequest(&provider_ptr),
+                                          kNoSessionId, kDeviceId,
+                                          mock_callback.Get());
+
+  EXPECT_CALL(mock_callback,
+              Run(Ne(media::OUTPUT_DEVICE_STATUS_OK), _, std::string()));
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(0u, factory.current_number_of_providers_for_testing());
+}
+
+TEST_F(RenderFrameAudioOutputStreamFactoryTest,
+       CreateStream_CreatesStreamAndFreesProvider) {
+  mojom::RendererAudioOutputStreamFactoryPtr factory_ptr;
+  RenderFrameAudioOutputStreamFactory factory(main_rfh(), audio_system_.get(),
+                                              media_stream_manager_.get(),
+                                              mojo::MakeRequest(&factory_ptr));
+
+  media::mojom::AudioOutputStreamProviderPtr provider_ptr;
+  MockAuthorizationCallback mock_callback;
+  factory_ptr->RequestDeviceAuthorization(mojo::MakeRequest(&provider_ptr),
+                                          kNoSessionId, kDefaultDeviceId,
+                                          mock_callback.Get());
+  {
+    media::mojom::AudioOutputStreamProviderClientPtr client;
+    mojo::MakeRequest(&client);
+    provider_ptr->Acquire(kParams, std::move(client));
   }
 
-  void Created(AudioOutputStreamPtr stream,
-               media::mojom::AudioDataPipePtr data_pipe) override {
-    was_called_ = true;
-    stream_ = std::move(stream);
+  audio::mojom::StreamFactory::CreateOutputStreamCallback created_callback;
+  EXPECT_CALL(mock_callback,
+              Run(media::OUTPUT_DEVICE_STATUS_OK, _, std::string()));
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(!!audio_service_stream_factory_.last_created_callback);
+  EXPECT_EQ(0u, factory.current_number_of_providers_for_testing());
+}
+
+TEST_F(RenderFrameAudioOutputStreamFactoryTest,
+       CreateStreamAfterFactoryDestruction_Fails) {
+  media::mojom::AudioOutputStreamProviderPtr provider_ptr;
+  MockAuthorizationCallback mock_callback;
+
+  {
+    mojom::RendererAudioOutputStreamFactoryPtr factory_ptr;
+    RenderFrameAudioOutputStreamFactory factory(
+        main_rfh(), audio_system_.get(), media_stream_manager_.get(),
+        mojo::MakeRequest(&factory_ptr));
+
+    factory_ptr->RequestDeviceAuthorization(mojo::MakeRequest(&provider_ptr),
+                                            kNoSessionId, kDefaultDeviceId,
+                                            mock_callback.Get());
+
+    audio::mojom::StreamFactory::CreateOutputStreamCallback created_callback;
+    EXPECT_CALL(mock_callback,
+                Run(media::OUTPUT_DEVICE_STATUS_OK, _, std::string()));
+    base::RunLoop().RunUntilIdle();
+  }
+  // Now factory is destructed. Trying to create a stream should fail.
+  {
+    media::mojom::AudioOutputStreamProviderClientPtr client;
+    mojo::MakeRequest(&client);
+    provider_ptr->Acquire(kParams, std::move(client));
   }
 
-  bool was_called() { return was_called_; }
-
-  MOCK_METHOD0(OnError, void());
-
- private:
-  mojo::Binding<AudioOutputStreamProviderClient> provider_client_binding_;
-  AudioOutputStreamPtr stream_;
-  bool was_called_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(MockClient);
-};
-
-void AuthCallback(media::OutputDeviceStatus* status_out,
-                  media::AudioParameters* params_out,
-                  std::string* id_out,
-                  media::OutputDeviceStatus status,
-                  const media::AudioParameters& params,
-                  const std::string& id) {
-  *status_out = status;
-  *params_out = params;
-  *id_out = id;
-}
-
-}  // namespace
-
-// This test authorizes and creates a stream, and checks that
-// 1. the ProviderClient callback is called with appropriate parameters.
-// 2. the AudioOutputDelegate is created.
-// 3. when the delegate calls OnStreamCreated, this is propagated to the client.
-TEST(RenderFrameAudioOutputStreamFactoryTest, CreateStream) {
-  content::TestBrowserThreadBundle thread_bundle;
-  AudioOutputStreamProviderPtr provider;
-  MockClient client;
-  media::AudioOutputDelegate::EventHandler* event_handler = nullptr;
-  auto factory_context = std::make_unique<MockContext>(true);
-  factory_context->PrepareDelegateForCreation(
-      std::make_unique<MockAudioOutputDelegate>(), &event_handler);
-  AudioOutputStreamFactoryPtr factory_ptr = factory_context->CreateFactory();
-
-  media::OutputDeviceStatus status;
-  media::AudioParameters params;
-  std::string id;
-  factory_ptr->RequestDeviceAuthorization(
-      mojo::MakeRequest(&provider), kNoSessionId, "default",
-      base::BindOnce(&AuthCallback, base::Unretained(&status),
-                     base::Unretained(&params), base::Unretained(&id)));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(status, media::OUTPUT_DEVICE_STATUS_OK);
-  EXPECT_EQ(params.AsHumanReadableString(),
-            GetTestAudioParameters().AsHumanReadableString());
-  EXPECT_TRUE(id.empty());
-
-  provider->Acquire(params, client.MakeProviderClientPtr());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_NE(event_handler, nullptr);
-
-  base::SharedMemory shared_memory;
-  ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(100));
-
-  auto local = std::make_unique<base::CancelableSyncSocket>();
-  auto remote = std::make_unique<base::CancelableSyncSocket>();
-  ASSERT_TRUE(
-      base::CancelableSyncSocket::CreatePair(local.get(), remote.get()));
-  event_handler->OnStreamCreated(kStreamId, &shared_memory, std::move(remote));
-
-  base::RunLoop().RunUntilIdle();
-  // Make sure we got the callback from creating stream.
-  EXPECT_TRUE(client.was_called());
-}
-
-TEST(RenderFrameAudioOutputStreamFactoryTest, NotAuthorized_Denied) {
-  content::TestBrowserThreadBundle thread_bundle;
-  AudioOutputStreamProviderPtr output_provider;
-  auto factory_context = std::make_unique<MockContext>(false);
-  AudioOutputStreamFactoryPtr factory_ptr = factory_context->CreateFactory();
-
-  media::OutputDeviceStatus status;
-  media::AudioParameters params;
-  std::string id;
-  factory_ptr->RequestDeviceAuthorization(
-      mojo::MakeRequest(&output_provider), kNoSessionId, "default",
-      base::BindOnce(&AuthCallback, base::Unretained(&status),
-                     base::Unretained(&params), base::Unretained(&id)));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(status, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED);
-  EXPECT_TRUE(id.empty());
-}
-
-TEST(RenderFrameAudioOutputStreamFactoryTest, ConnectionError_DeletesStream) {
-  content::TestBrowserThreadBundle thread_bundle;
-  AudioOutputStreamProviderPtr provider;
-  MockClient client;
-  bool delegate_is_destructed = false;
-  media::AudioOutputDelegate::EventHandler* event_handler = nullptr;
-  auto factory_context = std::make_unique<MockContext>(true);
-  factory_context->PrepareDelegateForCreation(
-      std::make_unique<MockAudioOutputDelegate>(
-          base::BindOnce([](bool* destructed) { *destructed = true; },
-                         &delegate_is_destructed)),
-      &event_handler);
-  AudioOutputStreamFactoryPtr factory_ptr = factory_context->CreateFactory();
-
-  factory_ptr->RequestDeviceAuthorization(
-      mojo::MakeRequest(&provider), kNoSessionId, "default",
-      base::BindOnce([](media::OutputDeviceStatus status,
-                        const media::AudioParameters& params,
-                        const std::string& id) {}));
   base::RunLoop().RunUntilIdle();
 
-  provider->Acquire(GetTestAudioParameters(), client.MakeProviderClientPtr());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_NE(event_handler, nullptr);
-  EXPECT_FALSE(delegate_is_destructed);
-  provider.reset();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(delegate_is_destructed);
-}
-
-TEST(RenderFrameAudioOutputStreamFactoryTest, DelegateError_DeletesStream) {
-  content::TestBrowserThreadBundle thread_bundle;
-  AudioOutputStreamProviderPtr provider;
-  MockClient client;
-  bool delegate_is_destructed = false;
-  media::AudioOutputDelegate::EventHandler* event_handler = nullptr;
-  auto factory_context = std::make_unique<MockContext>(true);
-  factory_context->PrepareDelegateForCreation(
-      std::make_unique<MockAudioOutputDelegate>(
-          base::BindOnce([](bool* destructed) { *destructed = true; },
-                         &delegate_is_destructed)),
-      &event_handler);
-  AudioOutputStreamFactoryPtr factory_ptr = factory_context->CreateFactory();
-
-  factory_ptr->RequestDeviceAuthorization(
-      mojo::MakeRequest(&provider), kNoSessionId, "default",
-      base::BindOnce([](media::OutputDeviceStatus status,
-                        const media::AudioParameters& params,
-                        const std::string& id) {}));
-  base::RunLoop().RunUntilIdle();
-
-  provider->Acquire(GetTestAudioParameters(), client.MakeProviderClientPtr());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_NE(event_handler, nullptr);
-  EXPECT_FALSE(delegate_is_destructed);
-  event_handler->OnStreamError(kStreamId);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(delegate_is_destructed);
+  EXPECT_FALSE(!!audio_service_stream_factory_.last_created_callback);
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h b/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h
index 5545740..923752d 100644
--- a/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h
+++ b/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h
@@ -21,6 +21,8 @@
 
 // RendererAudioOutputStreamFactoryContext provides functions common to all
 // AudioOutputFactory instances for a single renderer process.
+// Not needed after switching to serving audio streams with the audio service
+// (https://crbug.com/830493).
 class CONTENT_EXPORT RendererAudioOutputStreamFactoryContext {
  public:
   virtual ~RendererAudioOutputStreamFactoryContext() {}
diff --git a/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.cc b/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.cc
index 8492786..cfeb1aa5 100644
--- a/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.cc
+++ b/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.cc
@@ -9,7 +9,6 @@
 #include "content/browser/media/media_internals.h"
 #include "content/browser/renderer_host/media/audio_output_delegate_impl.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
-#include "content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/content_features.h"
 #include "media/audio/audio_system.h"
diff --git a/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.h b/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.h
index 3d06338c..6306946 100644
--- a/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.h
+++ b/content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.h
@@ -9,7 +9,7 @@
 #include <string>
 
 #include "content/browser/renderer_host/media/audio_output_authorization_handler.h"
-#include "content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h"
+#include "content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory.h"
 #include "content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -40,6 +40,8 @@
 //                 |
 // media::MojoAudioOutputStream
 //
+// Not needed after switching to serving audio streams with the audio service
+// (https://crbug.com/830493).
 class CONTENT_EXPORT RendererAudioOutputStreamFactoryContextImpl
     : public RendererAudioOutputStreamFactoryContext {
  public:
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 8a5c3e1..54864936 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -103,7 +103,6 @@
 #include "content/browser/media/midi_host.h"
 #include "content/browser/memory/memory_coordinator_impl.h"
 #include "content/browser/mime_registry_impl.h"
-#include "content/browser/notifications/notification_message_filter.h"
 #include "content/browser/payments/payment_manager.h"
 #include "content/browser/permissions/permission_service_context.h"
 #include "content/browser/permissions/permission_service_impl.h"
@@ -1865,10 +1864,6 @@
   scoped_refptr<ServiceWorkerContextWrapper> service_worker_context(
       static_cast<ServiceWorkerContextWrapper*>(
           storage_partition_impl_->GetServiceWorkerContext()));
-  notification_message_filter_ = new NotificationMessageFilter(
-      GetID(), storage_partition_impl_->GetPlatformNotificationContext(),
-      resource_context, service_worker_context, browser_context);
-  AddFilter(notification_message_filter_.get());
 }
 
 void RenderProcessHostImpl::BindCacheStorage(
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 403fcc6..3d2cc7c 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -75,7 +75,6 @@
 class GpuClientImpl;
 class IndexedDBDispatcherHost;
 class InProcessChildThreadParams;
-class NotificationMessageFilter;
 class PermissionServiceContext;
 class PeerConnectionTrackerHost;
 class PushMessagingManager;
@@ -334,10 +333,6 @@
     return render_frame_message_filter_.get();
   }
 
-  NotificationMessageFilter* notification_message_filter() const {
-    return notification_message_filter_.get();
-  }
-
   void SetBrowserPluginMessageFilterSubFilterForTesting(
       scoped_refptr<BrowserMessageFilter> message_filter) const;
 
@@ -684,10 +679,6 @@
 
   scoped_refptr<RenderFrameMessageFilter> render_frame_message_filter_;
 
-  // The filter for Web Notification messages coming from the renderer. Holds a
-  // closure per notification that must be freed when the notification closes.
-  scoped_refptr<NotificationMessageFilter> notification_message_filter_;
-
   // The filter for messages coming from the browser plugin.
   scoped_refptr<BrowserPluginMessageFilter> bp_message_filter_;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 51a6eae..a2712a0 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -237,48 +237,14 @@
   size_t processed_touch_event_count_;
 };
 
-class FakeDelegatedFrameHostClientAura
-    : public DelegatedFrameHostClientAura,
-      public ui::CompositorLockManagerClient {
+class FakeDelegatedFrameHostClientAura : public DelegatedFrameHostClientAura {
  public:
   explicit FakeDelegatedFrameHostClientAura(
       RenderWidgetHostViewAura* render_widget_host_view)
-      : DelegatedFrameHostClientAura(render_widget_host_view),
-        lock_manager_(new base::NullTaskRunner(), this) {}
+      : DelegatedFrameHostClientAura(render_widget_host_view) {}
   ~FakeDelegatedFrameHostClientAura() override = default;
 
-  void DisableResizeLock() { can_create_resize_lock_ = false; }
-
-  bool resize_locked() const { return resize_locked_; }
-  bool compositor_locked() const { return compositor_locked_; }
-
  private:
-  // CompositorResizeLockClient implemention. Overrides from
-  // DelegatedFrameHostClientAura, to prevent the lock from timing out.
-  std::unique_ptr<ui::CompositorLock> GetCompositorLock(
-      ui::CompositorLockClient* client) override {
-    resize_locked_ = compositor_locked_ = true;
-    return lock_manager_.GetCompositorLock(nullptr, base::TimeDelta());
-  }
-  // CompositorResizeLockClient implemention. Overrides from
-  // // DelegatedFrameHostClientAura.
-  void CompositorResizeLockEnded() override {
-    resize_locked_ = false;
-    DelegatedFrameHostClientAura::CompositorResizeLockEnded();
-  }
-
-  // ui::CompositorLockManagerClient implementation.
-  void OnCompositorLockStateChanged(bool locked) override {
-    if (!locked) {
-      compositor_locked_ = false;
-    }
-  }
-
-  bool can_create_resize_lock_ = true;
-  bool resize_locked_ = false;
-  bool compositor_locked_ = false;
-  ui::CompositorLockManager lock_manager_;
-
   DISALLOW_COPY_AND_ASSIGN(FakeDelegatedFrameHostClientAura);
 };
 
@@ -312,10 +278,6 @@
         renderer_compositor_frame_sink_ptr_.get());
   }
 
-  void DisableResizeLock() {
-    delegated_frame_host_client_->DisableResizeLock();
-  }
-
   void UseFakeDispatcher() {
     dispatcher_ = new FakeWindowEventDispatcher(window()->GetHost());
     std::unique_ptr<aura::WindowEventDispatcher> dispatcher(dispatcher_);
@@ -354,12 +316,6 @@
         metadata);
   }
 
-  bool resize_locked() const {
-    return delegated_frame_host_client_->resize_locked();
-  }
-  bool compositor_locked() const {
-    return delegated_frame_host_client_->compositor_locked();
-  }
   bool is_guest_view_hack() { return is_guest_view_hack_; }
 
   gfx::Size last_frame_size_;
@@ -3278,9 +3234,6 @@
   viz::LocalSurfaceId local_surface_id =
       parent_local_surface_id_allocator_.GenerateId();
 
-  // Prevent the DelegatedFrameHost from skipping frames.
-  view_->DisableResizeLock();
-
   view_->InitAsChild(nullptr);
   aura::client::ParentWindowWithContext(
       view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(),
@@ -3312,9 +3265,6 @@
   viz::LocalSurfaceId local_surface_id =
       parent_local_surface_id_allocator_.GenerateId();
 
-  // Prevent the DelegatedFrameHost from skipping frames.
-  view_->DisableResizeLock();
-
   view_->InitAsChild(nullptr);
   aura::client::ParentWindowWithContext(
       view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(),
@@ -3530,8 +3480,6 @@
       view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(),
       gfx::Rect());
 
-  // Prevent the DelegatedFrameHost from skipping frames.
-  view_->DisableResizeLock();
   ASSERT_TRUE(view_->delegated_frame_host_);
 
   view_->SetSize(gfx::Size(300, 300));
@@ -3569,9 +3517,6 @@
       view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(),
       gfx::Rect());
 
-  // Prevent the DelegatedFrameHost from skipping frames.
-  view_->DisableResizeLock();
-
   view_->SetSize(gfx::Size(300, 300));
   ASSERT_TRUE(view_->HasPrimarySurface());
   EXPECT_EQ(gfx::Size(300, 300), view_->window_->layer()->size());
@@ -3656,7 +3601,6 @@
     // run a UI compositor so the DelegatedFrameHost doesn't get the chance
     // to release its resize lock once it receives a frame of the expected
     // size.
-    views[i]->DisableResizeLock();
     views[i]->InitAsChild(nullptr);
     aura::client::ParentWindowWithContext(
         views[i]->GetNativeView(),
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 39aeeb3..5fccaf71 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -139,7 +139,7 @@
     ContentBrowserClient::NonNetworkURLLoaderFactoryMap factories;
     GetContentClient()
         ->browser()
-        ->RegisterNonNetworkNavigationURLLoaderFactories(
+        ->RegisterNonNetworkSubresourceURLLoaderFactories(
             rph->GetID(), MSG_ROUTING_NONE, &factories);
     auto iter = factories.find(params->script_url.scheme());
     if (iter != factories.end()) {
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc
index c2da069..3b5f8f1 100644
--- a/content/browser/service_worker/service_worker_context_core.cc
+++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -90,8 +90,6 @@
                                     ServiceWorkerProviderHost* host) {
   return host->IsProviderForClient() &&
          host->document_url().GetOrigin() == origin &&
-         // Don't expose "reserved" clients (clients that are not yet execution
-         // ready) to the Clients API.
          host->is_execution_ready();
 }
 
@@ -99,7 +97,8 @@
                                     ServiceWorkerProviderHost* host) {
   return host->provider_type() ==
              blink::mojom::ServiceWorkerProviderType::kForWindow &&
-         host->document_url().GetOrigin() == origin;
+         host->document_url().GetOrigin() == origin &&
+         host->is_execution_ready();
 }
 
 // Returns true if any of the frames specified by |frames| is a top-level frame.
@@ -366,6 +365,18 @@
   map->AddWithID(std::move(host), provider_id);
 }
 
+std::unique_ptr<ServiceWorkerProviderHost>
+ServiceWorkerContextCore::ReleaseProviderHost(int process_id, int provider_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  ProviderMap* map = GetProviderMapForProcess(process_id);
+  if (!map || !map->Lookup(provider_id))
+    return nullptr;
+  std::unique_ptr<ServiceWorkerProviderHost> host =
+      map->Replace(provider_id, nullptr);
+  map->Remove(provider_id);
+  return host;
+}
+
 ServiceWorkerProviderHost* ServiceWorkerContextCore::GetProviderHost(
     int process_id,
     int provider_id) {
@@ -609,33 +620,6 @@
   return (it != live_versions_.end()) ? it->second : nullptr;
 }
 
-// PlzNavigate
-void ServiceWorkerContextCore::AddNavigationHandleCore(
-    int service_worker_provider_id,
-    ServiceWorkerNavigationHandleCore* handle) {
-  auto result = navigation_handle_cores_map_.insert(
-      std::pair<int, ServiceWorkerNavigationHandleCore*>(
-          service_worker_provider_id, handle));
-  DCHECK(result.second)
-      << "Inserting a duplicate ServiceWorkerNavigationHandleCore";
-}
-
-// PlzNavigate
-void ServiceWorkerContextCore::RemoveNavigationHandleCore(
-    int service_worker_provider_id) {
-  navigation_handle_cores_map_.erase(service_worker_provider_id);
-}
-
-// PlzNavigate
-ServiceWorkerNavigationHandleCore*
-ServiceWorkerContextCore::GetNavigationHandleCore(
-    int service_worker_provider_id) {
-  auto result = navigation_handle_cores_map_.find(service_worker_provider_id);
-  if (result == navigation_handle_cores_map_.end())
-    return nullptr;
-  return result->second;
-}
-
 void ServiceWorkerContextCore::AddLiveVersion(ServiceWorkerVersion* version) {
   // TODO(horo): If we will see crashes here, we have to find the root cause of
   // the version ID conflict. Otherwise change CHECK to DCHECK.
diff --git a/content/browser/service_worker/service_worker_context_core.h b/content/browser/service_worker/service_worker_context_core.h
index 8268537..ea66452 100644
--- a/content/browser/service_worker/service_worker_context_core.h
+++ b/content/browser/service_worker/service_worker_context_core.h
@@ -45,7 +45,6 @@
 class ServiceWorkerContextWrapper;
 class ServiceWorkerDispatcherHost;
 class ServiceWorkerJobCoordinator;
-class ServiceWorkerNavigationHandleCore;
 class ServiceWorkerProviderHost;
 class ServiceWorkerRegistration;
 class ServiceWorkerStorage;
@@ -172,6 +171,9 @@
   void AddProviderHost(
       std::unique_ptr<ServiceWorkerProviderHost> provider_host);
   ServiceWorkerProviderHost* GetProviderHost(int process_id, int provider_id);
+  std::unique_ptr<ServiceWorkerProviderHost> ReleaseProviderHost(
+      int process_id,
+      int provider_id);
   void RemoveProviderHost(int process_id, int provider_id);
   void RemoveAllProviderHostsForProcess(int process_id);
 
@@ -184,7 +186,7 @@
 
   // Runs the callback with true if there is a ProviderHost for |origin| of type
   // blink::mojom::ServiceWorkerProviderType::kForWindow which is a main
-  // (top-level) frame.
+  // (top-level) frame. Reserved clients are ignored.
   void HasMainFrameProviderHost(const GURL& origin,
                                 BoolCallback callback) const;
 
@@ -245,15 +247,6 @@
     return live_versions_;
   }
 
-  // PlzNavigate
-  // Methods to manage the map keeping track of all
-  // ServiceWorkerNavigationHandleCores registered for ongoing navigations.
-  void AddNavigationHandleCore(int service_worker_provider_id,
-                               ServiceWorkerNavigationHandleCore* handle);
-  void RemoveNavigationHandleCore(int service_worker_provider_id);
-  ServiceWorkerNavigationHandleCore* GetNavigationHandleCore(
-      int service_worker_provider_id);
-
   std::vector<ServiceWorkerRegistrationInfo> GetAllLiveRegistrationInfo();
   std::vector<ServiceWorkerVersionInfo> GetAllLiveVersionInfo();
 
@@ -360,11 +353,6 @@
 
   std::map<int64_t /* version_id */, FailureInfo> failure_counts_;
 
-  // PlzNavigate
-  // Map of ServiceWorkerNavigationHandleCores used for navigation requests.
-  std::map<int, ServiceWorkerNavigationHandleCore*>
-      navigation_handle_cores_map_;
-
   // IsServicificationEnabled
   scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter_;
 
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc
index 9ad93b86..ef6b7926 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -139,13 +139,10 @@
       return;
     }
 
-    // Retrieve the provider host previously created for navigation requests.
-    std::unique_ptr<ServiceWorkerProviderHost> provider_host;
-    ServiceWorkerNavigationHandleCore* navigation_handle_core =
-        GetContext()->GetNavigationHandleCore(info.provider_id);
-    if (navigation_handle_core != nullptr)
-      provider_host = navigation_handle_core->RetrievePreCreatedHost();
-
+    // Retrieve the provider host pre-created for the navigation.
+    std::unique_ptr<ServiceWorkerProviderHost> provider_host =
+        GetContext()->ReleaseProviderHost(ChildProcessHost::kInvalidUniqueID,
+                                          info.provider_id);
     // If no host is found, create one.
     // TODO(crbug.com/789111#c14): This is probably not right, see bug.
     if (!provider_host) {
diff --git a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
index 3fd150f..a463143 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
@@ -198,7 +198,7 @@
   navigation_handle_core =
       CreateNavigationHandleCore(helper_->context_wrapper());
   ASSERT_TRUE(navigation_handle_core);
-  std::unique_ptr<ServiceWorkerProviderHost> host1 =
+  base::WeakPtr<ServiceWorkerProviderHost> host1 =
       ServiceWorkerProviderHost::PreCreateNavigationHost(
           context()->AsWeakPtr(), true /* are_ancestors_secure */,
           base::RepeatingCallback<WebContents*(void)>());
@@ -210,7 +210,7 @@
       host1->provider_id(), 1 /* route_id */, host1->provider_type(),
       host1->is_parent_frame_secure());
   RemoteProviderInfo remote_info_1 = SetupProviderHostInfoPtrs(&host_info_1);
-  navigation_handle_core->DidPreCreateProviderHost(std::move(host1));
+  navigation_handle_core->DidPreCreateProviderHost(host1->provider_id());
 
   dispatcher_host_->OnProviderCreated(std::move(host_info_1));
   EXPECT_TRUE(context()->GetProviderHost(process_id, kProviderId1));
@@ -229,8 +229,7 @@
   navigation_handle_core =
       CreateNavigationHandleCore(helper_->context_wrapper());
   ASSERT_TRUE(navigation_handle_core);
-  // ProviderHost should be created before OnProviderCreated.
-  std::unique_ptr<ServiceWorkerProviderHost> host2 =
+  base::WeakPtr<ServiceWorkerProviderHost> host2 =
       ServiceWorkerProviderHost::PreCreateNavigationHost(
           context()->AsWeakPtr(), true /* are_ancestors_secure */,
           base::RepeatingCallback<WebContents*(void)>());
@@ -239,7 +238,7 @@
       host2->provider_id(), 2 /* route_id */, host2->provider_type(),
       host2->is_parent_frame_secure());
   RemoteProviderInfo remote_info_2 = SetupProviderHostInfoPtrs(&host_info_2);
-  navigation_handle_core->DidPreCreateProviderHost(std::move(host2));
+  navigation_handle_core->DidPreCreateProviderHost(host2->provider_id());
 
   // Deletion of the dispatcher_host should cause providers for that
   // process to get deleted as well.
diff --git a/content/browser/service_worker/service_worker_navigation_handle.h b/content/browser/service_worker/service_worker_navigation_handle.h
index e1f32a8..fffae16 100644
--- a/content/browser/service_worker/service_worker_navigation_handle.h
+++ b/content/browser/service_worker/service_worker_navigation_handle.h
@@ -27,9 +27,9 @@
 //   2) When the navigation request is sent to the IO thread, we include a
 //   pointer to the ServiceWorkerNavigationHandleCore.
 //
-//   3) If we pre-create a ServiceWorkerProviderHost for this navigation, its
-//   ownership is passed to the ServiceWorkerNavigationHandleCore. The
-//   ServiceWorkerNavigationHandleCore id is updated.
+//   3) If we pre-create a ServiceWorkerProviderHost for this navigation, it
+//   is added to ServiceWorkerContextCore and the id is passed to
+//   ServiceWorkerNavigationHandleCore.
 //
 //   4) The ServiceWorkerNavigationHandleCore informs the
 //   ServiceWorkerNavigationHandle on the UI thread that the service worker
@@ -40,10 +40,11 @@
 //   ServiceWorkerNavigationHandle.
 //
 //   6) If the commit leads to the creation of a ServiceWorkerNetworkProvider
-//   in the renderer, a ServiceWorkerHostMsg_ProviderCreated will be received
-//   in the browser. The ServiceWorkerDispatcherHost will retrieve the
-//   ServiceWorkerProviderHost from the ServiceWorkerNavigationHandleCore and
-//   put it in the ServiceWorkerContextCore map of ServiceWorkerProviderHosts.
+//   in the renderer, an OnProviderCreated IPC will be received in the browser.
+//   The ServiceWorkerDispatcherHost will take the ServiceWorkerProviderHost
+//   from ServiceWorkerContextCore and complete its initialization, including
+//   setting the process id. It is then re-added to ServiceWorkerContextCore
+//   since it now has a correct process id.
 //
 //   7) When the navigation finishes, the ServiceWorkerNavigationHandle is
 //   destroyed. The destructor of the ServiceWorkerNavigationHandle posts a
diff --git a/content/browser/service_worker/service_worker_navigation_handle_core.cc b/content/browser/service_worker/service_worker_navigation_handle_core.cc
index a840a8aa..686fa131 100644
--- a/content/browser/service_worker/service_worker_navigation_handle_core.cc
+++ b/content/browser/service_worker/service_worker_navigation_handle_core.cc
@@ -12,7 +12,9 @@
 #include "content/browser/service_worker/service_worker_navigation_handle.h"
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/common/service_worker/service_worker_types.h"
+#include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/common/child_process_host.h"
 
 namespace content {
 
@@ -27,39 +29,28 @@
 
 ServiceWorkerNavigationHandleCore::~ServiceWorkerNavigationHandleCore() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (precreated_host_.get() && context_wrapper_->context()) {
-    context_wrapper_->context()->RemoveNavigationHandleCore(
-        precreated_host_->provider_id());
+  if (provider_id_ == kInvalidServiceWorkerProviderId)
+    return;
+  // Remove the provider host if it was never completed (navigation failed).
+  ServiceWorkerContextCore* context = context_wrapper_->context();
+  if (!context || !context->GetProviderHost(ChildProcessHost::kInvalidUniqueID,
+                                            provider_id_)) {
+    return;
   }
+  context->RemoveProviderHost(ChildProcessHost::kInvalidUniqueID, provider_id_);
 }
 
 void ServiceWorkerNavigationHandleCore::DidPreCreateProviderHost(
-    std::unique_ptr<ServiceWorkerProviderHost> precreated_host) {
+    int provider_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK(precreated_host.get());
-  DCHECK(context_wrapper_->context());
+  DCHECK(ServiceWorkerUtils::IsBrowserAssignedProviderId(provider_id));
 
-  precreated_host_ = std::move(precreated_host);
-  context_wrapper_->context()->AddNavigationHandleCore(
-      precreated_host_->provider_id(), this);
+  provider_id_ = provider_id;
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
       base::BindOnce(
           &ServiceWorkerNavigationHandle::DidCreateServiceWorkerProviderHost,
-          ui_handle_, precreated_host_->provider_id()));
-}
-
-std::unique_ptr<ServiceWorkerProviderHost>
-ServiceWorkerNavigationHandleCore::RetrievePreCreatedHost() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK(precreated_host_);
-  // Remove the ServiceWorkerNavigationHandleCore from the list of
-  // ServiceWorkerNavigationHandleCores since it will no longer hold a
-  // ServiceWorkerProviderHost.
-  DCHECK(context_wrapper_->context());
-  context_wrapper_->context()->RemoveNavigationHandleCore(
-      precreated_host_->provider_id());
-  return std::move(precreated_host_);
+          ui_handle_, provider_id_));
 }
 
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_navigation_handle_core.h b/content/browser/service_worker/service_worker_navigation_handle_core.h
index 8e98b05..ce581432 100644
--- a/content/browser/service_worker/service_worker_navigation_handle_core.h
+++ b/content/browser/service_worker/service_worker_navigation_handle_core.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "content/common/content_export.h"
+#include "content/common/service_worker/service_worker_types.h"
 
 namespace content {
 
@@ -33,21 +34,15 @@
   ~ServiceWorkerNavigationHandleCore();
 
   // Called when a ServiceWorkerProviderHost was pre-created for the navigation
-  // tracked by this ServiceWorkerNavigationHandleCore. Takes ownership of
-  // |precreated_host|.
-  void DidPreCreateProviderHost(
-      std::unique_ptr<ServiceWorkerProviderHost> precreated_host);
-
-  // Called when the renderer created a ServiceWorkerNetworkProvider matching
-  // |precreated_host_|. This releases ownership of |precreated_host_|.
-  std::unique_ptr<ServiceWorkerProviderHost> RetrievePreCreatedHost();
+  // tracked by this ServiceWorkerNavigationHandleCore.
+  void DidPreCreateProviderHost(int provider_id);
 
   ServiceWorkerContextWrapper* context_wrapper() const {
     return context_wrapper_.get();
   }
 
  private:
-  std::unique_ptr<ServiceWorkerProviderHost> precreated_host_;
+  int provider_id_ = kInvalidServiceWorkerProviderId;
   scoped_refptr<ServiceWorkerContextWrapper> context_wrapper_;
   base::WeakPtr<ServiceWorkerNavigationHandle> ui_handle_;
 
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index 383edb7..6123cef 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -169,11 +169,12 @@
 }  // anonymous namespace
 
 // static
-std::unique_ptr<ServiceWorkerProviderHost>
+base::WeakPtr<ServiceWorkerProviderHost>
 ServiceWorkerProviderHost::PreCreateNavigationHost(
     base::WeakPtr<ServiceWorkerContextCore> context,
     bool are_ancestors_secure,
     const WebContentsGetter& web_contents_getter) {
+  DCHECK(context);
   auto host = base::WrapUnique(new ServiceWorkerProviderHost(
       ChildProcessHost::kInvalidUniqueID,
       ServiceWorkerProviderHostInfo(
@@ -182,7 +183,10 @@
           are_ancestors_secure),
       context, nullptr /* dispatcher_host */));
   host->web_contents_getter_ = web_contents_getter;
-  return host;
+
+  auto weak_ptr = host->AsWeakPtr();
+  context->AddProviderHost(std::move(host));
+  return weak_ptr;
 }
 
 // static
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index 294b8c16..0a223f4 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -133,11 +133,16 @@
 
   // Used to pre-create a ServiceWorkerProviderHost for a navigation. The
   // ServiceWorkerNetworkProvider will later be created in the renderer, should
-  // the navigation succeed. |is_parent_frame_is_secure| should be true for main
+  // the navigation succeed. |are_ancestors_secure| should be true for main
   // frames. Otherwise it is true iff all ancestor frames of this frame have a
   // secure origin. |web_contents_getter| indicates the tab where the navigation
   // is occurring.
-  static std::unique_ptr<ServiceWorkerProviderHost> PreCreateNavigationHost(
+  //
+  // The returned host is owned by |context|. Upon successful navigation, the
+  // caller should remove it from |context| and re-add it after calling
+  // CompleteNavigationInitialized() to update it with the correct process id.
+  // If navigation fails, the caller should remove it from |context|.
+  static base::WeakPtr<ServiceWorkerProviderHost> PreCreateNavigationHost(
       base::WeakPtr<ServiceWorkerContextCore> context,
       bool are_ancestors_secure,
       const WebContentsGetter& web_contents_getter);
diff --git a/content/browser/service_worker/service_worker_provider_host_unittest.cc b/content/browser/service_worker/service_worker_provider_host_unittest.cc
index 2172214..f629f5d 100644
--- a/content/browser/service_worker/service_worker_provider_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_provider_host_unittest.cc
@@ -161,6 +161,24 @@
     return host_raw;
   }
 
+  void FinishNavigation(ServiceWorkerProviderHost* host,
+                        ServiceWorkerProviderHostInfo info) {
+    // In production code, the loader/request handler does this.
+    host->SetDocumentUrl(GURL("https://www.example.com/page"));
+    host->SetTopmostFrameUrl(GURL("https://www.example.com/page"));
+
+    // In production code, the OnProviderCreated IPC is received which
+    // does this.
+    std::unique_ptr<ServiceWorkerProviderHost> owned_host =
+        helper_->context()->ReleaseProviderHost(host->process_id(),
+                                                host->provider_id());
+    host->CompleteNavigationInitialized(
+        helper_->mock_render_process_id(), std::move(info),
+        helper_->GetDispatcherHostForProcess(helper_->mock_render_process_id())
+            ->AsWeakPtr());
+    helper_->context()->AddProviderHost(std::move(owned_host));
+  }
+
   blink::mojom::ServiceWorkerErrorType Register(
       mojom::ServiceWorkerContainerHost* container_host,
       GURL pattern,
@@ -255,7 +273,7 @@
       const GURL& document_url,
       const GURL& topmost_frame_url,
       ServiceWorkerRemoteProviderEndpoint* remote_endpoint) {
-    std::unique_ptr<ServiceWorkerProviderHost> host =
+    base::WeakPtr<ServiceWorkerProviderHost> host =
         ServiceWorkerProviderHost::PreCreateNavigationHost(
             helper_->context()->AsWeakPtr(), true,
             base::Callback<WebContents*(void)>());
@@ -264,16 +282,19 @@
         blink::mojom::ServiceWorkerProviderType::kForWindow,
         true /* is_parent_frame_secure */);
     remote_endpoint->BindWithProviderHostInfo(&info);
+
+    std::unique_ptr<ServiceWorkerProviderHost> owned_host =
+        helper_->context()->ReleaseProviderHost(host->process_id(),
+                                                host->provider_id());
     host->CompleteNavigationInitialized(
         helper_->mock_render_process_id(), std::move(info),
         helper_->GetDispatcherHostForProcess(helper_->mock_render_process_id())
             ->AsWeakPtr());
-
     host->SetDocumentUrl(document_url);
     host->SetTopmostFrameUrl(topmost_frame_url);
-    ServiceWorkerProviderHost* host_raw = host.get();
-    context_->AddProviderHost(std::move(host));
-    return host_raw;
+    helper_->context()->AddProviderHost(std::move(owned_host));
+
+    return host.get();
   }
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderHostTest);
@@ -407,7 +428,7 @@
 
 TEST_F(ServiceWorkerProviderHostTest, Controller) {
   // Create a host.
-  std::unique_ptr<ServiceWorkerProviderHost> host =
+  base::WeakPtr<ServiceWorkerProviderHost> host =
       ServiceWorkerProviderHost::PreCreateNavigationHost(
           helper_->context()->AsWeakPtr(), true /* are_ancestors_secure */,
           base::Callback<WebContents*(void)>());
@@ -427,12 +448,7 @@
   registration1_->SetActiveVersion(version);
 
   // Finish the navigation.
-  host->SetDocumentUrl(GURL("https://www.example.com/page"));
-  host->CompleteNavigationInitialized(
-      helper_->mock_render_process_id(), std::move(info),
-      helper_->GetDispatcherHostForProcess(helper_->mock_render_process_id())
-          ->AsWeakPtr());
-
+  FinishNavigation(host.get(), std::move(info));
   host->AssociateRegistration(registration1_.get(),
                               false /* notify_controllerchange */);
   base::RunLoop().RunUntilIdle();
@@ -446,7 +462,7 @@
 
 TEST_F(ServiceWorkerProviderHostTest, ActiveIsNotController) {
   // Create a host.
-  std::unique_ptr<ServiceWorkerProviderHost> host =
+  base::WeakPtr<ServiceWorkerProviderHost> host =
       ServiceWorkerProviderHost::PreCreateNavigationHost(
           helper_->context()->AsWeakPtr(), true /* are_ancestors_secure */,
           base::Callback<WebContents*(void)>());
@@ -467,12 +483,7 @@
 
 
   // Finish the navigation.
-  host->SetDocumentUrl(GURL("https://www.example.com/page"));
-  host->CompleteNavigationInitialized(
-      helper_->mock_render_process_id(), std::move(info),
-      helper_->GetDispatcherHostForProcess(helper_->mock_render_process_id())
-          ->AsWeakPtr());
-
+  FinishNavigation(host.get(), std::move(info));
   host->AssociateRegistration(registration1_.get(),
                               false /* notify_controllerchange */);
   // Promote the worker to active while navigation is still happening.
@@ -809,9 +820,9 @@
   EXPECT_EQ(1u, bad_messages_.size());
 }
 
-// Test that a "reserved" (i.e., not execution ready) shared worker client is
-// not included when iterating over client provider hosts. If it were, it'd be
-// undesirably exposed via the Clients API.
+// Test that a "reserved" (i.e., not execution ready) client is not included
+// when iterating over client provider hosts. If it were, it'd be undesirably
+// exposed via the Clients API.
 TEST_F(ServiceWorkerProviderHostTest,
        ReservedClientsAreNotExposedToClientsAPI) {
   {
@@ -828,7 +839,7 @@
   }
 
   {
-    std::unique_ptr<ServiceWorkerProviderHost> host =
+    base::WeakPtr<ServiceWorkerProviderHost> host =
         ServiceWorkerProviderHost::PreCreateNavigationHost(
             helper_->context()->AsWeakPtr(), true,
             base::RepeatingCallback<WebContents*(void)>());
@@ -841,13 +852,8 @@
     host->SetDocumentUrl(GURL("https://www.example.com/page"));
     EXPECT_FALSE(CanFindClientProviderHost(host.get()));
 
-    host->CompleteNavigationInitialized(
-        helper_->mock_render_process_id(), std::move(info),
-        helper_->GetDispatcherHostForProcess(helper_->mock_render_process_id())
-            ->AsWeakPtr());
-    auto* host_rawptr = host.get();
-    context_->AddProviderHost(std::move(host));
-    EXPECT_TRUE(CanFindClientProviderHost(host_rawptr));
+    FinishNavigation(host.get(), std::move(info));
+    EXPECT_TRUE(CanFindClientProviderHost(host.get()));
   }
 }
 
diff --git a/content/browser/service_worker/service_worker_request_handler.cc b/content/browser/service_worker/service_worker_request_handler.cc
index 7aaa707..379a90d 100644
--- a/content/browser/service_worker/service_worker_request_handler.cc
+++ b/content/browser/service_worker/service_worker_request_handler.cc
@@ -71,7 +71,6 @@
 // static
 int ServiceWorkerRequestHandler::user_data_key_;
 
-// PlzNavigate:
 // static
 void ServiceWorkerRequestHandler::InitializeForNavigation(
     net::URLRequest* request,
@@ -108,16 +107,17 @@
     return;
   }
 
-  if (!navigation_handle_core->context_wrapper() ||
-      !navigation_handle_core->context_wrapper()->context()) {
+  if (!navigation_handle_core->context_wrapper())
     return;
-  }
+  ServiceWorkerContextCore* context =
+      navigation_handle_core->context_wrapper()->context();
+  if (!context)
+    return;
 
   // Initialize the SWProviderHost.
-  std::unique_ptr<ServiceWorkerProviderHost> provider_host =
+  base::WeakPtr<ServiceWorkerProviderHost> provider_host =
       ServiceWorkerProviderHost::PreCreateNavigationHost(
-          navigation_handle_core->context_wrapper()->context()->AsWeakPtr(),
-          is_parent_frame_secure, web_contents_getter);
+          context->AsWeakPtr(), is_parent_frame_secure, web_contents_getter);
 
   std::unique_ptr<ServiceWorkerRequestHandler> handler(
       provider_host->CreateRequestHandler(
@@ -130,12 +130,8 @@
   if (handler)
     request->SetUserData(&user_data_key_, std::move(handler));
 
-  // Transfer ownership to the ServiceWorkerNavigationHandleCore.
-  // In the case of a successful navigation, the SWProviderHost will be
-  // transferred to its "final" destination in the OnProviderCreated handler. If
-  // the navigation fails, it will be destroyed along with the
-  // ServiceWorkerNavigationHandleCore.
-  navigation_handle_core->DidPreCreateProviderHost(std::move(provider_host));
+  navigation_handle_core->DidPreCreateProviderHost(
+      provider_host->provider_id());
 }
 
 // S13nServiceWorker:
@@ -163,13 +159,15 @@
     return nullptr;
   }
 
-  if (!navigation_handle_core->context_wrapper() ||
-      !navigation_handle_core->context_wrapper()->context()) {
+  if (!navigation_handle_core->context_wrapper())
     return nullptr;
-  }
+  ServiceWorkerContextCore* context =
+      navigation_handle_core->context_wrapper()->context();
+  if (!context)
+    return nullptr;
 
   // Initialize the SWProviderHost.
-  std::unique_ptr<ServiceWorkerProviderHost> provider_host =
+  base::WeakPtr<ServiceWorkerProviderHost> provider_host =
       ServiceWorkerProviderHost::PreCreateNavigationHost(
           navigation_handle_core->context_wrapper()->context()->AsWeakPtr(),
           is_parent_frame_secure, web_contents_getter);
@@ -183,12 +181,8 @@
           request_context_type, frame_type, blob_storage_context->AsWeakPtr(),
           body, skip_service_worker));
 
-  // Transfer ownership to the ServiceWorkerNavigationHandleCore.
-  // In the case of a successful navigation, the SWProviderHost will be
-  // transferred to its "final" destination in the OnProviderCreated handler. If
-  // the navigation fails, it will be destroyed along with the
-  // ServiceWorkerNavigationHandleCore.
-  navigation_handle_core->DidPreCreateProviderHost(std::move(provider_host));
+  navigation_handle_core->DidPreCreateProviderHost(
+      provider_host->provider_id());
 
   return base::WrapUnique<NavigationLoaderInterceptor>(handler.release());
 }
diff --git a/content/browser/web_package/signed_exchange_cert_fetcher.cc b/content/browser/web_package/signed_exchange_cert_fetcher.cc
index 2b81230..85c702a 100644
--- a/content/browser/web_package/signed_exchange_cert_fetcher.cc
+++ b/content/browser/web_package/signed_exchange_cert_fetcher.cc
@@ -11,6 +11,7 @@
 #include "base/trace_event/trace_event.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/web_package/signed_exchange_consts.h"
+#include "content/browser/web_package/signed_exchange_devtools_proxy.h"
 #include "content/browser/web_package/signed_exchange_utils.h"
 #include "content/common/throttling_url_loader.h"
 #include "content/public/common/resource_type.h"
@@ -109,11 +110,20 @@
         net::LOAD_DISABLE_CACHE | net::LOAD_BYPASS_CACHE;
   }
   resource_request_->render_frame_id = MSG_ROUTING_NONE;
+  if (devtools_proxy_) {
+    cert_request_id_ = base::UnguessableToken::Create();
+    resource_request_->enable_load_timing = true;
+  }
 }
 
 SignedExchangeCertFetcher::~SignedExchangeCertFetcher() = default;
 
 void SignedExchangeCertFetcher::Start() {
+  if (devtools_proxy_) {
+    DCHECK(cert_request_id_);
+    devtools_proxy_->CertificateRequestSent(*cert_request_id_,
+                                            *resource_request_);
+  }
   url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
       std::move(shared_url_loader_factory_), std::move(throttles_),
       0 /* routing_id */,
@@ -189,6 +199,11 @@
 void SignedExchangeCertFetcher::OnReceiveResponse(
     const network::ResourceResponseHead& head,
     network::mojom::DownloadedTempFilePtr downloaded_file) {
+  if (devtools_proxy_) {
+    DCHECK(cert_request_id_);
+    devtools_proxy_->CertificateResponseReceived(*cert_request_id_,
+                                                 resource_request_->url, head);
+  }
   TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("loading"),
                      "SignedExchangeCertFetcher::OnReceiveResponse");
   if (head.headers->response_code() != net::HTTP_OK) {
@@ -267,6 +282,10 @@
     const network::URLLoaderCompletionStatus& status) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
                "SignedExchangeCertFetcher::OnComplete");
+  if (devtools_proxy_) {
+    DCHECK(cert_request_id_);
+    devtools_proxy_->CertificateRequestCompleted(*cert_request_id_, status);
+  }
   if (!handle_watcher_)
     Abort();
 }
diff --git a/content/browser/web_package/signed_exchange_cert_fetcher.h b/content/browser/web_package/signed_exchange_cert_fetcher.h
index 8d02588..3e860f2c 100644
--- a/content/browser/web_package/signed_exchange_cert_fetcher.h
+++ b/content/browser/web_package/signed_exchange_cert_fetcher.h
@@ -12,6 +12,7 @@
 #include "base/callback_helpers.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "base/unguessable_token.h"
 #include "content/browser/web_package/signed_exchange_certificate_chain.h"
 #include "content/common/content_export.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
@@ -107,6 +108,7 @@
 
   // This is owned by SignedExchangeHandler which is the owner of |this|.
   SignedExchangeDevToolsProxy* devtools_proxy_;
+  base::Optional<base::UnguessableToken> cert_request_id_;
 
   DISALLOW_COPY_AND_ASSIGN(SignedExchangeCertFetcher);
 };
diff --git a/content/browser/web_package/signed_exchange_devtools_proxy.cc b/content/browser/web_package/signed_exchange_devtools_proxy.cc
index 4d48eb0..3a012e4 100644
--- a/content/browser/web_package/signed_exchange_devtools_proxy.cc
+++ b/content/browser/web_package/signed_exchange_devtools_proxy.cc
@@ -28,6 +28,45 @@
       content::CONSOLE_MESSAGE_LEVEL_ERROR, error_message);
 }
 
+void CertificateRequestSentOnUI(
+    base::RepeatingCallback<int(void)> frame_tree_node_id_getter,
+    const base::UnguessableToken& request_id,
+    const base::UnguessableToken& loader_id,
+    const network::ResourceRequest& request) {
+  FrameTreeNode* frame_tree_node =
+      FrameTreeNode::GloballyFindByID(frame_tree_node_id_getter.Run());
+  if (!frame_tree_node)
+    return;
+  RenderFrameDevToolsAgentHost::OnSignedExchangeCertificateRequestSent(
+      frame_tree_node, request_id, loader_id, request);
+}
+
+void CertificateResponseReceivedOnUI(
+    base::RepeatingCallback<int(void)> frame_tree_node_id_getter,
+    const base::UnguessableToken& request_id,
+    const base::UnguessableToken& loader_id,
+    const GURL& url,
+    scoped_refptr<network::ResourceResponse> response) {
+  FrameTreeNode* frame_tree_node =
+      FrameTreeNode::GloballyFindByID(frame_tree_node_id_getter.Run());
+  if (!frame_tree_node)
+    return;
+  RenderFrameDevToolsAgentHost::OnSignedExchangeCertificateResponseReceived(
+      frame_tree_node, request_id, loader_id, url, response->head);
+}
+
+void CertificateRequestCompletedOnUI(
+    base::RepeatingCallback<int(void)> frame_tree_node_id_getter,
+    const base::UnguessableToken& request_id,
+    const network::URLLoaderCompletionStatus& status) {
+  FrameTreeNode* frame_tree_node =
+      FrameTreeNode::GloballyFindByID(frame_tree_node_id_getter.Run());
+  if (!frame_tree_node)
+    return;
+  RenderFrameDevToolsAgentHost::OnSignedExchangeCertificateRequestCompleted(
+      frame_tree_node, request_id, status);
+}
+
 void OnSignedExchangeReceivedOnUI(
     base::RepeatingCallback<int(void)> frame_tree_node_id_getter,
     const GURL& outer_request_url,
@@ -71,6 +110,51 @@
                      std::move(message)));
 }
 
+void SignedExchangeDevToolsProxy::CertificateRequestSent(
+    const base::UnguessableToken& request_id,
+    const network::ResourceRequest& request) {
+  if (!devtools_enabled_)
+    return;
+
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::BindOnce(
+          &CertificateRequestSentOnUI, frame_tree_node_id_getter_, request_id,
+          devtools_navigation_token_ ? *devtools_navigation_token_ : request_id,
+          request));
+}
+
+void SignedExchangeDevToolsProxy::CertificateResponseReceived(
+    const base::UnguessableToken& request_id,
+    const GURL& url,
+    const network::ResourceResponseHead& head) {
+  if (!devtools_enabled_)
+    return;
+
+  // Make a deep copy of ResourceResponseHead before passing it cross-thread.
+  auto resource_response = base::MakeRefCounted<network::ResourceResponse>();
+  resource_response->head = head;
+
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::BindOnce(
+          &CertificateResponseReceivedOnUI, frame_tree_node_id_getter_,
+          request_id,
+          devtools_navigation_token_ ? *devtools_navigation_token_ : request_id,
+          url, resource_response->DeepCopy()));
+}
+
+void SignedExchangeDevToolsProxy::CertificateRequestCompleted(
+    const base::UnguessableToken& request_id,
+    const network::URLLoaderCompletionStatus& status) {
+  if (!devtools_enabled_)
+    return;
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::BindOnce(&CertificateRequestCompletedOnUI,
+                     frame_tree_node_id_getter_, request_id, status));
+}
+
 void SignedExchangeDevToolsProxy::OnSignedExchangeReceived(
     const base::Optional<SignedExchangeHeader>& header) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
diff --git a/content/browser/web_package/signed_exchange_devtools_proxy.h b/content/browser/web_package/signed_exchange_devtools_proxy.h
index ae376c7..be90dfd3 100644
--- a/content/browser/web_package/signed_exchange_devtools_proxy.h
+++ b/content/browser/web_package/signed_exchange_devtools_proxy.h
@@ -21,7 +21,9 @@
 }  // namespace base
 
 namespace network {
+struct ResourceRequest;
 struct ResourceResponseHead;
+struct URLLoaderCompletionStatus;
 }  // namespace network
 
 namespace content {
@@ -50,6 +52,14 @@
   ~SignedExchangeDevToolsProxy();
 
   void ReportErrorMessage(const std::string& message);
+  void CertificateRequestSent(const base::UnguessableToken& request_id,
+                              const network::ResourceRequest& request);
+  void CertificateResponseReceived(const base::UnguessableToken& request_id,
+                                   const GURL& url,
+                                   const network::ResourceResponseHead& head);
+  void CertificateRequestCompleted(
+      const base::UnguessableToken& request_id,
+      const network::URLLoaderCompletionStatus& status);
 
   void OnSignedExchangeReceived(
       const base::Optional<SignedExchangeHeader>& header);
diff --git a/content/browser/web_package/signed_exchange_handler.cc b/content/browser/web_package/signed_exchange_handler.cc
index 19655c99..9b60011 100644
--- a/content/browser/web_package/signed_exchange_handler.cc
+++ b/content/browser/web_package/signed_exchange_handler.cc
@@ -4,7 +4,6 @@
 
 #include "content/browser/web_package/signed_exchange_handler.h"
 
-#include "base/feature_list.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
@@ -19,7 +18,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/common/content_features.h"
 #include "content/public/common/url_loader_throttle.h"
 #include "mojo/public/cpp/system/string_data_pipe_producer.h"
 #include "net/base/io_buffer.h"
@@ -87,7 +85,7 @@
           net::NetLogSourceType::CERT_VERIFIER_JOB)),
       devtools_proxy_(std::move(devtools_proxy)),
       weak_factory_(this) {
-  DCHECK(base::FeatureList::IsEnabled(features::kSignedHTTPExchange));
+  DCHECK(signed_exchange_utils::IsSignedExchangeHandlingEnabled());
   TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("loading"),
                      "SignedExchangeHandler::SignedExchangeHandler");
 
diff --git a/content/browser/web_package/signed_exchange_url_loader_factory_for_non_network_service.cc b/content/browser/web_package/signed_exchange_url_loader_factory_for_non_network_service.cc
index d30ea2d..08476ba 100644
--- a/content/browser/web_package/signed_exchange_url_loader_factory_for_non_network_service.cc
+++ b/content/browser/web_package/signed_exchange_url_loader_factory_for_non_network_service.cc
@@ -7,6 +7,7 @@
 #include "base/feature_list.h"
 #include "content/browser/loader/resource_requester_info.h"
 #include "content/browser/loader/url_loader_factory_impl.h"
+#include "content/browser/web_package/signed_exchange_utils.h"
 #include "content/public/common/content_features.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/features.h"
@@ -20,7 +21,7 @@
     : resource_context_(resource_context),
       url_request_context_getter_(url_request_context_getter) {
   DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
-  DCHECK(base::FeatureList::IsEnabled(features::kSignedHTTPExchange));
+  DCHECK(signed_exchange_utils::IsSignedExchangeHandlingEnabled());
 }
 
 SignedExchangeURLLoaderFactoryForNonNetworkService::
diff --git a/content/browser/web_package/signed_exchange_utils.cc b/content/browser/web_package/signed_exchange_utils.cc
index e2ab00e5..4086fd6 100644
--- a/content/browser/web_package/signed_exchange_utils.cc
+++ b/content/browser/web_package/signed_exchange_utils.cc
@@ -4,8 +4,14 @@
 
 #include "content/browser/web_package/signed_exchange_utils.h"
 
+#include "base/feature_list.h"
+#include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "content/browser/web_package/signed_exchange_devtools_proxy.h"
+#include "content/browser/web_package/web_package_request_handler.h"
+#include "content/public/common/content_features.h"
+#include "services/network/public/cpp/resource_response.h"
+#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
 
 namespace content {
 namespace signed_exchange_utils {
@@ -19,5 +25,31 @@
                    "error", error_message);
 }
 
+bool IsSignedExchangeHandlingEnabled() {
+  return base::FeatureList::IsEnabled(features::kSignedHTTPExchange) ||
+         base::FeatureList::IsEnabled(features::kSignedHTTPExchangeOriginTrial);
+}
+
+bool ShouldHandleAsSignedHTTPExchange(
+    const GURL& request_url,
+    const network::ResourceResponseHead& head) {
+  // Currently we don't support the signed exchange which is returned from a
+  // service worker.
+  // TODO(crbug/803774): Decide whether we should support it or not.
+  if (head.was_fetched_via_service_worker)
+    return false;
+  if (!WebPackageRequestHandler::IsSupportedMimeType(head.mime_type))
+    return false;
+  if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange))
+    return true;
+  if (!base::FeatureList::IsEnabled(features::kSignedHTTPExchangeOriginTrial))
+    return false;
+  std::unique_ptr<blink::TrialTokenValidator> validator =
+      std::make_unique<blink::TrialTokenValidator>();
+  return validator->RequestEnablesFeature(request_url, head.headers.get(),
+                                          features::kSignedHTTPExchange.name,
+                                          base::Time::Now());
+}
+
 }  // namespace signed_exchange_utils
 }  // namespace content
diff --git a/content/browser/web_package/signed_exchange_utils.h b/content/browser/web_package/signed_exchange_utils.h
index c1ce564c..b5c4220 100644
--- a/content/browser/web_package/signed_exchange_utils.h
+++ b/content/browser/web_package/signed_exchange_utils.h
@@ -7,6 +7,12 @@
 
 #include <string>
 
+class GURL;
+
+namespace network {
+struct ResourceResponseHead;
+}  // namespace network
+
 namespace content {
 
 class SignedExchangeDevToolsProxy;
@@ -20,6 +26,18 @@
                                  const char* trace_event_name,
                                  const std::string& error_message);
 
+// Returns true when SignedHTTPExchange feature or SignedHTTPExchangeOriginTrial
+// feature is enabled.
+bool IsSignedExchangeHandlingEnabled();
+
+// Returns true when the response should be handled as a signed exchange by
+// checking the mime type and the feature flags. When SignedHTTPExchange feature
+// is not enabled and SignedHTTPExchangeOriginTrial feature is enabled, this
+// method also checks the Origin Trial header.
+bool ShouldHandleAsSignedHTTPExchange(
+    const GURL& request_url,
+    const network::ResourceResponseHead& head);
+
 }  // namespace  signed_exchange_utils
 }  // namespace content
 
diff --git a/content/browser/web_package/web_package_loader.cc b/content/browser/web_package/web_package_loader.cc
index abd5fed5..3192cfc 100644
--- a/content/browser/web_package/web_package_loader.cc
+++ b/content/browser/web_package/web_package_loader.cc
@@ -14,6 +14,7 @@
 #include "content/browser/web_package/signed_exchange_cert_fetcher_factory.h"
 #include "content/browser/web_package/signed_exchange_devtools_proxy.h"
 #include "content/browser/web_package/signed_exchange_handler.h"
+#include "content/browser/web_package/signed_exchange_utils.h"
 #include "content/public/common/content_features.h"
 #include "net/cert/cert_status_flags.h"
 #include "net/http/http_util.h"
@@ -98,7 +99,7 @@
       url_loader_throttles_getter_(std::move(url_loader_throttles_getter)),
       request_context_getter_(std::move(request_context_getter)),
       weak_factory_(this) {
-  DCHECK(base::FeatureList::IsEnabled(features::kSignedHTTPExchange));
+  DCHECK(signed_exchange_utils::IsSignedExchangeHandlingEnabled());
 
   // Can't use HttpResponseHeaders::GetMimeType() because SignedExchangeHandler
   // checks "v=" parameter.
diff --git a/content/browser/web_package/web_package_prefetch_handler.cc b/content/browser/web_package/web_package_prefetch_handler.cc
index 6c8f207f..b8ced15c 100644
--- a/content/browser/web_package/web_package_prefetch_handler.cc
+++ b/content/browser/web_package/web_package_prefetch_handler.cc
@@ -5,10 +5,10 @@
 #include "content/browser/web_package/web_package_prefetch_handler.h"
 
 #include "base/callback.h"
+#include "base/feature_list.h"
 #include "content/browser/web_package/signed_exchange_devtools_proxy.h"
 #include "content/browser/web_package/signed_exchange_url_loader_factory_for_non_network_service.h"
 #include "content/browser/web_package/web_package_loader.h"
-#include "content/browser/web_package/web_package_request_handler.h"
 #include "content/public/common/content_features.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/url_request/url_request_context_getter.h"
@@ -18,18 +18,6 @@
 
 namespace content {
 
-bool WebPackagePrefetchHandler::IsResponseForWebPackage(
-    const network::ResourceResponseHead& response) {
-  std::string mime_type;
-  if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange) &&
-      !response.was_fetched_via_service_worker && response.headers &&
-      response.headers->GetMimeType(&mime_type) &&
-      WebPackageRequestHandler::IsSupportedMimeType(mime_type)) {
-    return true;
-  }
-  return false;
-}
-
 WebPackagePrefetchHandler::WebPackagePrefetchHandler(
     base::RepeatingCallback<int(void)> frame_tree_node_id_getter,
     bool report_raw_headers,
diff --git a/content/browser/web_package/web_package_prefetch_handler.h b/content/browser/web_package/web_package_prefetch_handler.h
index 4527372..f6fc27c 100644
--- a/content/browser/web_package/web_package_prefetch_handler.h
+++ b/content/browser/web_package/web_package_prefetch_handler.h
@@ -30,9 +30,6 @@
   using URLLoaderThrottlesGetter = base::RepeatingCallback<
       std::vector<std::unique_ptr<content::URLLoaderThrottle>>()>;
 
-  static bool IsResponseForWebPackage(
-      const network::ResourceResponseHead& response);
-
   // This takes |network_loader| and |network_client| to set up the
   // WebPackageLoader (so that the loader can load data from the network).
   // |forwarding_client| is a pointer to the downstream client (typically who
diff --git a/content/browser/web_package/web_package_request_handler.cc b/content/browser/web_package/web_package_request_handler.cc
index 591dec1ee..f67d3068 100644
--- a/content/browser/web_package/web_package_request_handler.cc
+++ b/content/browser/web_package/web_package_request_handler.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "content/browser/web_package/signed_exchange_devtools_proxy.h"
+#include "content/browser/web_package/signed_exchange_utils.h"
 #include "content/browser/web_package/web_package_loader.h"
 #include "content/common/throttling_url_loader.h"
 #include "content/public/common/content_features.h"
@@ -18,13 +19,13 @@
 #include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
+#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
 
 namespace content {
 
 // static
 bool WebPackageRequestHandler::IsSupportedMimeType(
     const std::string& mime_type) {
-  DCHECK(base::FeatureList::IsEnabled(features::kSignedHTTPExchange));
   return mime_type == "application/signed-exchange";
 }
 
@@ -48,7 +49,7 @@
       url_loader_throttles_getter_(std::move(url_loader_throttles_getter)),
       request_context_getter_(std::move(request_context_getter)),
       weak_factory_(this) {
-  DCHECK(base::FeatureList::IsEnabled(features::kSignedHTTPExchange));
+  DCHECK(signed_exchange_utils::IsSignedExchangeHandlingEnabled());
 }
 
 WebPackageRequestHandler::~WebPackageRequestHandler() = default;
@@ -75,10 +76,8 @@
     network::mojom::URLLoaderPtr* loader,
     network::mojom::URLLoaderClientRequest* client_request,
     ThrottlingURLLoader* url_loader) {
-  std::string mime_type;
-  if (response.was_fetched_via_service_worker || !response.headers ||
-      !response.headers->GetMimeType(&mime_type) ||
-      !IsSupportedMimeType(mime_type)) {
+  if (!signed_exchange_utils::ShouldHandleAsSignedHTTPExchange(
+          request_initiator_.GetURL(), response)) {
     return false;
   }
 
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index de18c89..d6e4bedc 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -326,9 +326,6 @@
       WebRuntimeFeatures::EnableGenericSensorExtraClasses(true);
   }
 
-  if (base::FeatureList::IsEnabled(features::kNotificationsWithMojo))
-    WebRuntimeFeatures::EnableNotificationsWithMojo(true);
-
   if (base::FeatureList::IsEnabled(network::features::kOutOfBlinkCORS))
     WebRuntimeFeatures::EnableOutOfBlinkCORS(true);
 
diff --git a/content/common/platform_notification_messages.h b/content/common/platform_notification_messages.h
index 507b4fb0..b925cdcd 100644
--- a/content/common/platform_notification_messages.h
+++ b/content/common/platform_notification_messages.h
@@ -17,19 +17,10 @@
 #include "content/public/common/platform_notification_data.h"
 #include "ipc/ipc_message_macros.h"
 
-// Singly-included section for type definitions.
-#ifndef INTERNAL_CONTENT_COMMON_PLATFORM_NOTIFICATION_MESSAGES_H_
-#define INTERNAL_CONTENT_COMMON_PLATFORM_NOTIFICATION_MESSAGES_H_
-
-// Defines the pair of [notification id] => [notification data] used when
-// getting the notifications for a given Service Worker registration.
-using PersistentNotificationInfo =
-    std::pair<std::string, content::PlatformNotificationData>;
-
-#endif  // INTERNAL_CONTENT_COMMON_PLATFORM_NOTIFICATION_MESSAGES_H_
-
 #define IPC_MESSAGE_START PlatformNotificationMsgStart
 
+// TODO(https://crbug.com/841329): Delete this legacy IPC code, use a pure
+// mojo struct instead from ServiceWorkerEventDispatcher mojo interface.
 IPC_ENUM_TRAITS_MAX_VALUE(
     content::PlatformNotificationData::Direction,
     content::PlatformNotificationData::DIRECTION_LAST)
@@ -63,48 +54,4 @@
   IPC_STRUCT_TRAITS_MEMBER(actions)
 IPC_STRUCT_TRAITS_END()
 
-IPC_STRUCT_TRAITS_BEGIN(content::NotificationResources)
-  IPC_STRUCT_TRAITS_MEMBER(image)
-  IPC_STRUCT_TRAITS_MEMBER(notification_icon)
-  IPC_STRUCT_TRAITS_MEMBER(badge)
-  IPC_STRUCT_TRAITS_MEMBER(action_icons)
-IPC_STRUCT_TRAITS_END()
-
-// Messages sent from the browser to the renderer.
-
-// Reply to PlatformNotificationHostMsg_ShowPersistent indicating that a
-// persistent notification has been shown on the platform (if |success| is
-// true), or that an unspecified error occurred.
-IPC_MESSAGE_CONTROL2(PlatformNotificationMsg_DidShowPersistent,
-                     int /* request_id */,
-                     bool /* success */)
-
-// Reply to PlatformNotificationHostMsg_GetNotifications sharing a vector of
-// available notifications per the request's constraints.
-IPC_MESSAGE_CONTROL2(PlatformNotificationMsg_DidGetNotifications,
-                     int /* request_id */,
-                     std::vector<PersistentNotificationInfo>
-                         /* notifications */)
-
-// Messages sent from the renderer to the browser.
-
-IPC_MESSAGE_CONTROL5(
-    PlatformNotificationHostMsg_ShowPersistent,
-    int /* request_id */,
-    int64_t /* service_worker_registration_id */,
-    GURL /* origin */,
-    content::PlatformNotificationData /* notification_data */,
-    content::NotificationResources /* notification_resources */)
-
-IPC_MESSAGE_CONTROL4(PlatformNotificationHostMsg_GetNotifications,
-                     int /* request_id */,
-                     int64_t /* service_worker_registration_id */,
-                     GURL /* origin */,
-                     std::string /* filter_tag */)
-
-IPC_MESSAGE_CONTROL3(PlatformNotificationHostMsg_ClosePersistent,
-                     GURL /* origin */,
-                     std::string /* tag */,
-                     std::string /* notification_id */)
-
 #endif  // CONTENT_COMMON_PLATFORM_NOTIFICATION_MESSAGES_H_
diff --git a/content/common/service_worker/service_worker_utils.h b/content/common/service_worker/service_worker_utils.h
index 349136eb..e7ce9c97 100644
--- a/content/common/service_worker/service_worker_utils.h
+++ b/content/common/service_worker/service_worker_utils.h
@@ -51,7 +51,6 @@
   // Returns true if servicified service worker is enabled.
   CONTENT_EXPORT static bool IsServicificationEnabled();
 
-  // PlzNavigate
   // Returns true if the |provider_id| was assigned by the browser process.
   static bool IsBrowserAssignedProviderId(int provider_id) {
     return provider_id < kInvalidServiceWorkerProviderId;
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
index ae520378ef..06dc311 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
@@ -199,7 +199,6 @@
         try {
             TraceEvent.begin("ContentViewCore.onConfigurationChanged");
             getImeAdapter().onKeyboardConfigurationChanged(newConfig);
-            mContainerViewInternals.super_onConfigurationChanged(newConfig);
             // To request layout has side effect, but it seems OK as it only happen in
             // onConfigurationChange and layout has to be changed in most case.
             ViewAndroidDelegate viewDelegate = mWebContents.getViewAndroidDelegate();
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content_public/browser/ContentViewCore.java
index ebe041b0..509b42c 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/ContentViewCore.java
@@ -70,11 +70,6 @@
         boolean super_onGenericMotionEvent(MotionEvent event);
 
         /**
-         * @see View#onConfigurationChanged(Configuration)
-         */
-        void super_onConfigurationChanged(Configuration newConfig);
-
-        /**
          * @see View#onScrollChanged(int, int, int, int)
          */
         void onScrollChanged(int lPix, int tPix, int oldlPix, int oldtPix);
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
index 672c99c..577b644 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
@@ -4,7 +4,6 @@
 
 package org.chromium.content.browser;
 
-import android.content.res.Configuration;
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
@@ -68,10 +67,6 @@
         }
 
         @Override
-        public void super_onConfigurationChanged(Configuration newConfig) {
-        }
-
-        @Override
         public void onScrollChanged(int lPix, int tPix, int oldlPix, int oldtPix) {
             synchronized (mLock) {
                 mScrollChanged = true;
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index 01d495e..e3c4a13 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -74,7 +74,7 @@
       },
       "requires": {
         "*": [ "app" ],
-        "audio": [ "info", "debug_recording"],
+        "audio": [ "info", "debug_recording", "stream_factory"],
         "cdm": [ "media:cdm" ],
         "content_gpu": [ "browser" ],
         "content_plugin": [ "browser" ],
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 1cb6291..c5f889b3 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -595,13 +595,12 @@
 }
 
 void ContentBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories(
-    int render_process_id,
-    int render_frame_id,
+    int frame_tree_node_id,
     NonNetworkURLLoaderFactoryMap* factories) {}
 
 void ContentBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
-    RenderFrameHost* frame_host,
-    const GURL& frame_url,
+    int render_process_id,
+    int render_frame_id,
     NonNetworkURLLoaderFactoryMap* factories) {}
 
 bool ContentBrowserClient::WillCreateURLLoaderFactory(
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 2dc3bf7..d9bd9f1c 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -989,21 +989,23 @@
   // Allows the embedder to register per-scheme URLLoaderFactory implementations
   // to handle navigation URL requests for schemes not handled by the Network
   // Service. Only called when the Network Service is enabled.
+  // Note that a RenderFrameHost or RenderProcessHost aren't passed in because
+  // these can change during a navigation (e.g. depending on redirects).
   using NonNetworkURLLoaderFactoryMap =
       std::map<std::string, std::unique_ptr<network::mojom::URLLoaderFactory>>;
   virtual void RegisterNonNetworkNavigationURLLoaderFactories(
-      int render_process_id,
-      int render_frame_id,
+      int frame_tree_node_id,
       NonNetworkURLLoaderFactoryMap* factories);
 
   // Allows the embedder to register per-scheme URLLoaderFactory implementations
   // to handle subresource URL requests for schemes not handled by the Network
-  // Service. The factories added to this map will only be used to service
-  // subresource requests from |frame_host| as long as it's navigated to
-  // |frame_url|. Only called when the Network Service is enabled.
+  // Service. This function can also be used to make a factory for other
+  // non-subresource requests, such as for the service worker script when
+  // starting a service worker. In that case, the frame id will be
+  // MSG_ROUTING_NONE.
   virtual void RegisterNonNetworkSubresourceURLLoaderFactories(
-      RenderFrameHost* frame_host,
-      const GURL& frame_url,
+      int render_process_id,
+      int render_frame_id,
       NonNetworkURLLoaderFactoryMap* factories);
 
   // Allows the embedder to intercept URLLoaderFactory interfaces used for
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 5c9bb09..f51735f 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -36,6 +36,10 @@
 const base::Feature kAsyncWheelEvents{"AsyncWheelEvents",
                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Creates audio output and input streams using the audio service.
+const base::Feature kAudioServiceAudioStreams{
+    "AudioServiceAudioStreams", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Runs the audio service in a separate process.
 const base::Feature kAudioServiceOutOfProcess{
     "AudioServiceOutOfProcess", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -233,10 +237,6 @@
 const base::Feature kNotificationContentImage{"NotificationContentImage",
                                               base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Use Mojo IPC for notifications.
-const base::Feature kNotificationsWithMojo{"NotificationsWithMojo",
-                                           base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Off-main-thread WebSocket. See https://crbug.com/825740
 const base::Feature kOffMainThreadWebSocket{"OffMainThreadWebSocket",
                                             base::FEATURE_ENABLED_BY_DEFAULT};
@@ -356,6 +356,10 @@
 const base::Feature kSignedHTTPExchange{"SignedHTTPExchange",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Origin Trial of Origin-Signed HTTP Exchanges (for WebPackage Loading)
+const base::Feature kSignedHTTPExchangeOriginTrial{
+    "SignedHTTPExchangeOriginTrial", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // An experiment to require process isolation for the sign-in origin,
 // https://accounts.google.com.  Launch bug: https://crbug.com/739418.
 const base::Feature kSignInProcessIsolation{"sign-in-process-isolation",
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index c328fb68..93afde5 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -22,6 +22,7 @@
 CONTENT_EXPORT extern const base::Feature kArrayPrototypeValues;
 CONTENT_EXPORT extern const base::Feature kAsmJsToWebAssembly;
 CONTENT_EXPORT extern const base::Feature kAsyncWheelEvents;
+CONTENT_EXPORT extern const base::Feature kAudioServiceAudioStreams;
 CONTENT_EXPORT extern const base::Feature kAudioServiceOutOfProcess;
 CONTENT_EXPORT extern const base::Feature kBlockCredentialedSubresources;
 CONTENT_EXPORT extern const base::Feature kBrotliEncoding;
@@ -60,7 +61,6 @@
 CONTENT_EXPORT extern const base::Feature kMojoVideoCapture;
 CONTENT_EXPORT extern const base::Feature kNetworkServiceInProcess;
 CONTENT_EXPORT extern const base::Feature kNotificationContentImage;
-CONTENT_EXPORT extern const base::Feature kNotificationsWithMojo;
 CONTENT_EXPORT extern const base::Feature kOffMainThreadWebSocket;
 CONTENT_EXPORT extern const base::Feature kOriginManifest;
 CONTENT_EXPORT extern const base::Feature kOriginTrials;
@@ -87,6 +87,7 @@
 CONTENT_EXPORT extern const base::Feature kServiceWorkerServicification;
 CONTENT_EXPORT extern const base::Feature kSharedArrayBuffer;
 CONTENT_EXPORT extern const base::Feature kSignedHTTPExchange;
+CONTENT_EXPORT extern const base::Feature kSignedHTTPExchangeOriginTrial;
 CONTENT_EXPORT extern const base::Feature kSignInProcessIsolation;
 CONTENT_EXPORT extern const base::Feature kSlimmingPaintV175;
 CONTENT_EXPORT extern const base::Feature kSpareRendererForSitePerProcess;
diff --git a/content/public/test/test_download_http_response.cc b/content/public/test/test_download_http_response.cc
index 9e4347f..1cd615a 100644
--- a/content/public/test/test_download_http_response.cc
+++ b/content/public/test/test_download_http_response.cc
@@ -121,7 +121,6 @@
       size(102400),
       pattern_generator_seed(1),
       support_byte_ranges(true),
-      support_partial_response(true),
       connection_type(
           net::HttpResponseInfo::ConnectionInfo::CONNECTION_INFO_UNKNOWN) {}
 
@@ -137,7 +136,6 @@
       size(that.size),
       pattern_generator_seed(that.pattern_generator_seed),
       support_byte_ranges(that.support_byte_ranges),
-      support_partial_response(that.support_partial_response),
       connection_type(that.connection_type),
       static_response(std::move(that.static_response)),
       injected_errors(std::move(that.injected_errors)),
@@ -148,12 +146,11 @@
 TestDownloadHttpResponse::Parameters& TestDownloadHttpResponse::Parameters::
 operator=(Parameters&& that) {
   etag = std::move(that.etag);
-  last_modified = std::move(that.last_modified);
+  last_modified = std::move(that.etag);
   content_type = std::move(that.content_type);
   size = that.size;
   pattern_generator_seed = that.pattern_generator_seed;
   support_byte_ranges = that.support_byte_ranges;
-  support_partial_response = that.support_partial_response;
   static_response = std::move(that.static_response);
   injected_errors = std::move(that.injected_errors);
   inject_error_cb = that.inject_error_cb;
@@ -300,8 +297,7 @@
   // Adjust the response range according to request range. The first byte offset
   // of the request may be larger than entity body size.
   request_range_ = ranges[0];
-  if (parameters_.support_partial_response)
-    range_.set_first_byte_position(request_range_.first_byte_position());
+  range_.set_first_byte_position(request_range_.first_byte_position());
   range_.ComputeBounds(parameters_.size);
 
   response_sent_offset_ = range_.first_byte_position();
@@ -329,7 +325,7 @@
 std::string TestDownloadHttpResponse::GetDefaultResponseHeaders() {
   std::string headers;
   // Send partial response.
-  if (parameters_.support_partial_response && parameters_.support_byte_ranges &&
+  if (parameters_.support_byte_ranges &&
       request_.headers.find(net::HttpRequestHeaders::kIfRange) !=
           request_.headers.end() &&
       request_.headers.at(net::HttpRequestHeaders::kIfRange) ==
@@ -339,7 +335,7 @@
   }
 
   // Send precondition failed for "If-Match" request header.
-  if (parameters_.support_partial_response && parameters_.support_byte_ranges &&
+  if (parameters_.support_byte_ranges &&
       request_.headers.find(net::HttpRequestHeaders::kIfMatch) !=
           request_.headers.end()) {
     if (request_.headers.at(net::HttpRequestHeaders::kIfMatch) !=
diff --git a/content/public/test/test_download_http_response.h b/content/public/test/test_download_http_response.h
index 0ab178d..6fb801d8 100644
--- a/content/public/test/test_download_http_response.h
+++ b/content/public/test/test_download_http_response.h
@@ -108,12 +108,6 @@
     // response, or contains 'Content-Range' header for HTTP 206 response.
     bool support_byte_ranges;
 
-    // Whether the server supports partial range responses. A server can claim
-    // it support byte ranges, but actually doesn't send partial responses. In
-    // that case, Set |support_byte_ranges| to true and this variable to false
-    // to simulate the case.
-    bool support_partial_response;
-
     // The connection type in the response.
     net::HttpResponseInfo::ConnectionInfo connection_type;
 
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index fee5fc9c..a3c82ae 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -494,10 +494,6 @@
     "net_info_helper.h",
     "notifications/notification_data_conversions.cc",
     "notifications/notification_data_conversions.h",
-    "notifications/notification_dispatcher.cc",
-    "notifications/notification_dispatcher.h",
-    "notifications/notification_manager.cc",
-    "notifications/notification_manager.h",
     "p2p/empty_network_manager.cc",
     "p2p/empty_network_manager.h",
     "p2p/filtering_network_manager.cc",
diff --git a/content/renderer/loader/child_url_loader_factory_bundle.cc b/content/renderer/loader/child_url_loader_factory_bundle.cc
index feb92de..2ef16e2f 100644
--- a/content/renderer/loader/child_url_loader_factory_bundle.cc
+++ b/content/renderer/loader/child_url_loader_factory_bundle.cc
@@ -186,32 +186,12 @@
 
 std::unique_ptr<network::SharedURLLoaderFactoryInfo>
 ChildURLLoaderFactoryBundle::Clone() {
-  InitDefaultBlobFactoryIfNecessary();
-  InitDirectNetworkFactoryIfNecessary();
+  return CloneInternal(true /* include_default */);
+}
 
-  network::mojom::URLLoaderFactoryPtrInfo default_factory_info;
-  if (default_factory_)
-    default_factory_->Clone(mojo::MakeRequest(&default_factory_info));
-
-  std::map<std::string, network::mojom::URLLoaderFactoryPtrInfo> factories_info;
-  for (auto& factory : factories_) {
-    network::mojom::URLLoaderFactoryPtrInfo factory_info;
-    factory.second->Clone(mojo::MakeRequest(&factory_info));
-    factories_info.emplace(factory.first, std::move(factory_info));
-  }
-
-  network::mojom::URLLoaderFactoryPtrInfo direct_network_factory_info;
-  if (direct_network_factory_) {
-    direct_network_factory_->Clone(
-        mojo::MakeRequest(&direct_network_factory_info));
-  }
-
-  // Currently there is no need to override subresources from workers,
-  // therefore |subresource_overrides| are not shared with the clones.
-
-  return std::make_unique<ChildURLLoaderFactoryBundleInfo>(
-      std::move(default_factory_info), std::move(factories_info),
-      std::move(direct_network_factory_info));
+std::unique_ptr<network::SharedURLLoaderFactoryInfo>
+ChildURLLoaderFactoryBundle::CloneWithoutDefaultFactory() {
+  return CloneInternal(false /* include_default */);
 }
 
 void ChildURLLoaderFactoryBundle::Update(
@@ -260,6 +240,36 @@
   }
 }
 
+std::unique_ptr<network::SharedURLLoaderFactoryInfo>
+ChildURLLoaderFactoryBundle::CloneInternal(bool include_default) {
+  InitDefaultBlobFactoryIfNecessary();
+  InitDirectNetworkFactoryIfNecessary();
+
+  network::mojom::URLLoaderFactoryPtrInfo default_factory_info;
+  if (include_default && default_factory_)
+    default_factory_->Clone(mojo::MakeRequest(&default_factory_info));
+
+  std::map<std::string, network::mojom::URLLoaderFactoryPtrInfo> factories_info;
+  for (auto& factory : factories_) {
+    network::mojom::URLLoaderFactoryPtrInfo factory_info;
+    factory.second->Clone(mojo::MakeRequest(&factory_info));
+    factories_info.emplace(factory.first, std::move(factory_info));
+  }
+
+  network::mojom::URLLoaderFactoryPtrInfo direct_network_factory_info;
+  if (direct_network_factory_) {
+    direct_network_factory_->Clone(
+        mojo::MakeRequest(&direct_network_factory_info));
+  }
+
+  // Currently there is no need to override subresources from workers,
+  // therefore |subresource_overrides| are not shared with the clones.
+
+  return std::make_unique<ChildURLLoaderFactoryBundleInfo>(
+      std::move(default_factory_info), std::move(factories_info),
+      std::move(direct_network_factory_info));
+}
+
 std::unique_ptr<ChildURLLoaderFactoryBundleInfo>
 ChildURLLoaderFactoryBundle::PassInterface() {
   InitDefaultBlobFactoryIfNecessary();
diff --git a/content/renderer/loader/child_url_loader_factory_bundle.h b/content/renderer/loader/child_url_loader_factory_bundle.h
index 922cca48..cb613cb 100644
--- a/content/renderer/loader/child_url_loader_factory_bundle.h
+++ b/content/renderer/loader/child_url_loader_factory_bundle.h
@@ -83,6 +83,11 @@
 
   std::unique_ptr<network::SharedURLLoaderFactoryInfo> Clone() override;
 
+  // Returns an info that omits this bundle's default factory, if any. This is
+  // useful to make a clone that bypasses AppCache, for example.
+  std::unique_ptr<network::SharedURLLoaderFactoryInfo>
+  CloneWithoutDefaultFactory();
+
   std::unique_ptr<ChildURLLoaderFactoryBundleInfo> PassInterface();
 
   void Update(std::unique_ptr<ChildURLLoaderFactoryBundleInfo> info,
@@ -97,6 +102,8 @@
  private:
   void InitDefaultBlobFactoryIfNecessary();
   void InitDirectNetworkFactoryIfNecessary();
+  std::unique_ptr<network::SharedURLLoaderFactoryInfo> CloneInternal(
+      bool include_default);
 
   PossiblyAssociatedFactoryGetterCallback direct_network_factory_getter_;
   PossiblyAssociatedURLLoaderFactoryPtr direct_network_factory_;
diff --git a/content/renderer/notifications/notification_data_conversions.cc b/content/renderer/notifications/notification_data_conversions.cc
index 638a5e55..65556cd4 100644
--- a/content/renderer/notifications/notification_data_conversions.cc
+++ b/content/renderer/notifications/notification_data_conversions.cc
@@ -19,66 +19,6 @@
 
 namespace content {
 
-PlatformNotificationData ToPlatformNotificationData(
-    const WebNotificationData& web_data) {
-  PlatformNotificationData platform_data;
-  platform_data.title = web_data.title.Utf16();
-
-  switch (web_data.direction) {
-    case WebNotificationData::kDirectionLeftToRight:
-      platform_data.direction =
-          PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT;
-      break;
-    case WebNotificationData::kDirectionRightToLeft:
-      platform_data.direction =
-          PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT;
-      break;
-    case WebNotificationData::kDirectionAuto:
-      platform_data.direction = PlatformNotificationData::DIRECTION_AUTO;
-      break;
-  }
-
-  platform_data.lang = web_data.lang.Utf8(
-      WebString::UTF8ConversionMode::kStrictReplacingErrorsWithFFFD);
-  platform_data.body = web_data.body.Utf16();
-  platform_data.tag = web_data.tag.Utf8(
-      WebString::UTF8ConversionMode::kStrictReplacingErrorsWithFFFD);
-  platform_data.image = WebStringToGURL(web_data.image.GetString());
-  platform_data.icon = WebStringToGURL(web_data.icon.GetString());
-  platform_data.badge = WebStringToGURL(web_data.badge.GetString());
-  platform_data.vibration_pattern.assign(web_data.vibrate.begin(),
-                                         web_data.vibrate.end());
-  platform_data.timestamp = base::Time::FromJsTime(web_data.timestamp);
-  platform_data.renotify = web_data.renotify;
-  platform_data.silent = web_data.silent;
-  platform_data.require_interaction = web_data.require_interaction;
-  platform_data.data.assign(web_data.data.begin(), web_data.data.end());
-  platform_data.actions.resize(web_data.actions.size());
-  for (size_t i = 0; i < web_data.actions.size(); ++i) {
-    switch (web_data.actions[i].type) {
-      case blink::WebNotificationAction::kButton:
-        platform_data.actions[i].type =
-            PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
-        break;
-      case blink::WebNotificationAction::kText:
-        platform_data.actions[i].type = PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
-        break;
-      default:
-        NOTREACHED() << "Unknown notification action type: "
-                     << web_data.actions[i].type;
-    }
-    platform_data.actions[i].action = web_data.actions[i].action.Utf8(
-        WebString::UTF8ConversionMode::kStrictReplacingErrorsWithFFFD);
-    platform_data.actions[i].title = web_data.actions[i].title.Utf16();
-    platform_data.actions[i].icon =
-        WebStringToGURL(web_data.actions[i].icon.GetString());
-    platform_data.actions[i].placeholder =
-        WebString::ToNullableString16(web_data.actions[i].placeholder);
-  }
-
-  return platform_data;
-}
-
 WebNotificationData ToWebNotificationData(
     const PlatformNotificationData& platform_data) {
   WebNotificationData web_data;
diff --git a/content/renderer/notifications/notification_data_conversions.h b/content/renderer/notifications/notification_data_conversions.h
index 1d7c7a1..d6bf25e 100644
--- a/content/renderer/notifications/notification_data_conversions.h
+++ b/content/renderer/notifications/notification_data_conversions.h
@@ -11,10 +11,6 @@
 
 namespace content {
 
-// Converts Blink WebNotificationData to PlatformNotificationData.
-CONTENT_EXPORT PlatformNotificationData
-ToPlatformNotificationData(const blink::WebNotificationData& web_data);
-
 // Converts PlatformNotificationData to Blink WebNotificationData.
 CONTENT_EXPORT blink::WebNotificationData ToWebNotificationData(
     const PlatformNotificationData& platform_data);
diff --git a/content/renderer/notifications/notification_data_conversions_unittest.cc b/content/renderer/notifications/notification_data_conversions_unittest.cc
index 7d5eb0c..35fd3f2b 100644
--- a/content/renderer/notifications/notification_data_conversions_unittest.cc
+++ b/content/renderer/notifications/notification_data_conversions_unittest.cc
@@ -36,77 +36,6 @@
 const char kAction2Title[] = "Button 2";
 const char kAction2IconUrl[] = "https://example.com/action_icon_2.png";
 
-TEST(NotificationDataConversionsTest, ToPlatformNotificationData) {
-  blink::WebNotificationData web_data;
-  web_data.title = blink::WebString::FromUTF8(kNotificationTitle);
-  web_data.direction = blink::WebNotificationData::kDirectionLeftToRight;
-  web_data.lang = blink::WebString::FromUTF8(kNotificationLang);
-  web_data.body = blink::WebString::FromUTF8(kNotificationBody);
-  web_data.tag = blink::WebString::FromUTF8(kNotificationTag);
-  web_data.image = blink::WebURL(GURL(kNotificationImageUrl));
-  web_data.icon = blink::WebURL(GURL(kNotificationIconUrl));
-  web_data.badge = blink::WebURL(GURL(kNotificationBadgeUrl));
-  web_data.vibrate = blink::WebVector<int>(
-      kNotificationVibrationPattern, arraysize(kNotificationVibrationPattern));
-  web_data.timestamp = kNotificationTimestamp;
-  web_data.renotify = true;
-  web_data.silent = true;
-  web_data.require_interaction = true;
-  web_data.data =
-      blink::WebVector<char>(kNotificationData, arraysize(kNotificationData));
-
-  web_data.actions =
-      blink::WebVector<blink::WebNotificationAction>(static_cast<size_t>(2));
-  web_data.actions[0].type = blink::WebNotificationAction::kButton;
-  web_data.actions[0].action = blink::WebString::FromUTF8(kAction1Name);
-  web_data.actions[0].title = blink::WebString::FromUTF8(kAction1Title);
-  web_data.actions[0].icon = blink::WebURL(GURL(kAction1IconUrl));
-  web_data.actions[0].placeholder =
-      blink::WebString::FromUTF8(kAction1Placeholder);
-  web_data.actions[1].type = blink::WebNotificationAction::kText;
-  web_data.actions[1].action = blink::WebString::FromUTF8(kAction2Name);
-  web_data.actions[1].title = blink::WebString::FromUTF8(kAction2Title);
-  web_data.actions[1].icon = blink::WebURL(GURL(kAction2IconUrl));
-  web_data.actions[1].placeholder = blink::WebString();
-
-  PlatformNotificationData platform_data = ToPlatformNotificationData(web_data);
-  EXPECT_EQ(base::ASCIIToUTF16(kNotificationTitle), platform_data.title);
-  EXPECT_EQ(PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT,
-            platform_data.direction);
-  EXPECT_EQ(kNotificationLang, platform_data.lang);
-  EXPECT_EQ(base::ASCIIToUTF16(kNotificationBody), platform_data.body);
-  EXPECT_EQ(kNotificationTag, platform_data.tag);
-  EXPECT_EQ(kNotificationImageUrl, platform_data.image.spec());
-  EXPECT_EQ(kNotificationIconUrl, platform_data.icon.spec());
-  EXPECT_EQ(kNotificationBadgeUrl, platform_data.badge.spec());
-  EXPECT_TRUE(platform_data.renotify);
-  EXPECT_TRUE(platform_data.silent);
-  EXPECT_TRUE(platform_data.require_interaction);
-
-  EXPECT_THAT(platform_data.vibration_pattern,
-              testing::ElementsAreArray(kNotificationVibrationPattern));
-
-  EXPECT_DOUBLE_EQ(kNotificationTimestamp, platform_data.timestamp.ToJsTime());
-  ASSERT_EQ(web_data.data.size(), platform_data.data.size());
-  for (size_t i = 0; i < web_data.data.size(); ++i)
-    EXPECT_EQ(web_data.data[i], platform_data.data[i]);
-  ASSERT_EQ(web_data.actions.size(), platform_data.actions.size());
-  EXPECT_EQ(PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON,
-            platform_data.actions[0].type);
-  EXPECT_EQ(kAction1Name, platform_data.actions[0].action);
-  EXPECT_EQ(base::ASCIIToUTF16(kAction1Title), platform_data.actions[0].title);
-  EXPECT_EQ(kAction1IconUrl, platform_data.actions[0].icon.spec());
-  EXPECT_EQ(base::ASCIIToUTF16(kAction1Placeholder),
-            platform_data.actions[0].placeholder.string());
-  EXPECT_FALSE(platform_data.actions[0].placeholder.is_null());
-  EXPECT_EQ(PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT,
-            platform_data.actions[1].type);
-  EXPECT_EQ(kAction2Name, platform_data.actions[1].action);
-  EXPECT_EQ(base::ASCIIToUTF16(kAction2Title), platform_data.actions[1].title);
-  EXPECT_EQ(kAction2IconUrl, platform_data.actions[1].icon.spec());
-  EXPECT_TRUE(platform_data.actions[1].placeholder.is_null());
-}
-
 TEST(NotificationDataConversionsTest, ToWebNotificationData) {
   std::vector<int> vibration_pattern(
       kNotificationVibrationPattern,
@@ -180,72 +109,4 @@
   EXPECT_TRUE(web_data.actions[1].placeholder.IsNull());
 }
 
-TEST(NotificationDataConversionsTest, NotificationDataDirectionality) {
-  std::map<blink::WebNotificationData::Direction,
-           PlatformNotificationData::Direction> mappings;
-
-  mappings[blink::WebNotificationData::kDirectionLeftToRight] =
-      PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT;
-  mappings[blink::WebNotificationData::kDirectionRightToLeft] =
-      PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT;
-  mappings[blink::WebNotificationData::kDirectionAuto] =
-      PlatformNotificationData::DIRECTION_AUTO;
-
-  for (const auto& pair : mappings) {
-    {
-      blink::WebNotificationData web_data;
-      web_data.direction = pair.first;
-
-      PlatformNotificationData platform_data =
-          ToPlatformNotificationData(web_data);
-      EXPECT_EQ(pair.second, platform_data.direction);
-    }
-    {
-      PlatformNotificationData platform_data;
-      platform_data.direction = pair.second;
-
-      blink::WebNotificationData web_data =
-          ToWebNotificationData(platform_data);
-      EXPECT_EQ(pair.first, web_data.direction);
-    }
-  }
-}
-
-TEST(NotificationDataConversionsTest, TimeEdgeCaseValueBehaviour) {
-  {
-    blink::WebNotificationData web_data;
-    web_data.timestamp =
-        static_cast<double>(std::numeric_limits<unsigned long long>::max());
-
-    blink::WebNotificationData copied_data =
-        ToWebNotificationData(ToPlatformNotificationData(web_data));
-    EXPECT_NE(web_data.timestamp, copied_data.timestamp);
-  }
-  {
-    blink::WebNotificationData web_data;
-    web_data.timestamp =
-        static_cast<double>(9211726771200000000ull);  // January 1, 293878
-
-    blink::WebNotificationData copied_data =
-        ToWebNotificationData(ToPlatformNotificationData(web_data));
-    EXPECT_NE(web_data.timestamp, copied_data.timestamp);
-  }
-  {
-    blink::WebNotificationData web_data;
-    web_data.timestamp = 0;
-
-    blink::WebNotificationData copied_data =
-        ToWebNotificationData(ToPlatformNotificationData(web_data));
-    EXPECT_EQ(web_data.timestamp, copied_data.timestamp);
-  }
-  {
-    blink::WebNotificationData web_data;
-    web_data.timestamp = 0;
-
-    blink::WebNotificationData copied_data =
-        ToWebNotificationData(ToPlatformNotificationData(web_data));
-    EXPECT_EQ(web_data.timestamp, copied_data.timestamp);
-  }
-}
-
 }  // namespace content
diff --git a/content/renderer/notifications/notification_dispatcher.cc b/content/renderer/notifications/notification_dispatcher.cc
deleted file mode 100644
index 9508f95e7..0000000
--- a/content/renderer/notifications/notification_dispatcher.cc
+++ /dev/null
@@ -1,57 +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 "content/renderer/notifications/notification_dispatcher.h"
-
-#include <limits>
-
-#include "content/renderer/notifications/notification_manager.h"
-
-namespace content {
-
-NotificationDispatcher::NotificationDispatcher(
-    ThreadSafeSender* thread_safe_sender,
-    scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner)
-    : WorkerThreadMessageFilter(thread_safe_sender,
-                                std::move(main_thread_task_runner)) {}
-
-NotificationDispatcher::~NotificationDispatcher() {}
-
-int NotificationDispatcher::GenerateNotificationRequestId(int thread_id) {
-  base::AutoLock lock(notification_request_id_map_lock_);
-  CHECK_LT(next_notification_request_id_, std::numeric_limits<int>::max());
-
-  notification_request_id_map_[next_notification_request_id_] = thread_id;
-  return next_notification_request_id_++;
-}
-
-bool NotificationDispatcher::ShouldHandleMessage(
-    const IPC::Message& msg) const {
-  return IPC_MESSAGE_CLASS(msg) == PlatformNotificationMsgStart;
-}
-
-void NotificationDispatcher::OnFilteredMessageReceived(
-    const IPC::Message& msg) {
-  NotificationManager::ThreadSpecificInstance(thread_safe_sender(), this)
-      ->OnMessageReceived(msg);
-}
-
-bool NotificationDispatcher::GetWorkerThreadIdForMessage(
-    const IPC::Message& msg,
-    int* ipc_thread_id) {
-  int notification_request_id = -1;
-  const bool success =
-      base::PickleIterator(msg).ReadInt(&notification_request_id);
-  DCHECK(success);
-
-  base::AutoLock lock(notification_request_id_map_lock_);
-  auto iterator = notification_request_id_map_.find(notification_request_id);
-  if (iterator != notification_request_id_map_.end()) {
-    *ipc_thread_id = iterator->second;
-    return true;
-  }
-  return false;
-}
-
-}  // namespace content
diff --git a/content/renderer/notifications/notification_dispatcher.h b/content/renderer/notifications/notification_dispatcher.h
deleted file mode 100644
index c4da9ca..0000000
--- a/content/renderer/notifications/notification_dispatcher.h
+++ /dev/null
@@ -1,49 +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 CONTENT_RENDERER_NOTIFICATIONS_NOTIFICATION_DISPATCHER_H_
-#define CONTENT_RENDERER_NOTIFICATIONS_NOTIFICATION_DISPATCHER_H_
-
-#include <map>
-
-#include "base/macros.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/lock.h"
-#include "content/renderer/worker_thread_message_filter.h"
-
-namespace content {
-
-class NotificationDispatcher : public WorkerThreadMessageFilter {
- public:
-  NotificationDispatcher(
-      ThreadSafeSender* thread_safe_sender,
-      scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner);
-
-  // Generates and stores a new process-unique notification request ID mapped to
-  // |thread_id|, and returns the generated request ID. This method can be
-  // called on any thread.
-  int GenerateNotificationRequestId(int thread_id);
-
- protected:
-  ~NotificationDispatcher() override;
-
- private:
-  // WorkerThreadMessageFilter:
-  bool ShouldHandleMessage(const IPC::Message& msg) const override;
-  void OnFilteredMessageReceived(const IPC::Message& msg) override;
-  bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
-                                   int* ipc_thread_id) override;
-
-  using NotificationRequestIdToThreadId = std::map<int, int>;
-
-  base::Lock notification_request_id_map_lock_;
-  NotificationRequestIdToThreadId notification_request_id_map_;
-  int next_notification_request_id_ = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(NotificationDispatcher);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_NOTIFICATIONS_NOTIFICATION_DISPATCHER_H_
diff --git a/content/renderer/notifications/notification_manager.cc b/content/renderer/notifications/notification_manager.cc
deleted file mode 100644
index 831ef01..0000000
--- a/content/renderer/notifications/notification_manager.cc
+++ /dev/null
@@ -1,223 +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 "content/renderer/notifications/notification_manager.h"
-
-#include <utility>
-
-#include "base/lazy_instance.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_local.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/public/common/notification_resources.h"
-#include "content/public/common/platform_notification_data.h"
-#include "content/renderer/notifications/notification_data_conversions.h"
-#include "content/renderer/notifications/notification_dispatcher.h"
-#include "content/renderer/service_worker/web_service_worker_registration_impl.h"
-#include "third_party/blink/public/platform/modules/notifications/notification.mojom.h"
-#include "third_party/blink/public/platform/url_conversion.h"
-#include "third_party/blink/public/platform/web_security_origin.h"
-#include "url/origin.h"
-
-using blink::WebString;
-
-namespace content {
-namespace {
-
-int NotificationWorkerId() {
-  return WorkerThread::GetCurrentId();
-}
-
-NotificationResources ToNotificationResources(
-    std::unique_ptr<blink::WebNotificationResources> web_resources) {
-  NotificationResources resources;
-  resources.image = web_resources->image;
-  resources.notification_icon = web_resources->icon;
-  resources.badge = web_resources->badge;
-  for (const auto& action_icon : web_resources->action_icons)
-    resources.action_icons.push_back(action_icon);
-  return resources;
-}
-
-}  // namespace
-
-static base::LazyInstance<base::ThreadLocalPointer<NotificationManager>>::Leaky
-    g_notification_manager_tls = LAZY_INSTANCE_INITIALIZER;
-
-NotificationManager::NotificationManager(
-    ThreadSafeSender* thread_safe_sender,
-    NotificationDispatcher* notification_dispatcher)
-    : thread_safe_sender_(thread_safe_sender),
-      notification_dispatcher_(notification_dispatcher) {
-  g_notification_manager_tls.Pointer()->Set(this);
-}
-
-NotificationManager::~NotificationManager() {
-  g_notification_manager_tls.Pointer()->Set(nullptr);
-}
-
-NotificationManager* NotificationManager::ThreadSpecificInstance(
-    ThreadSafeSender* thread_safe_sender,
-    NotificationDispatcher* notification_dispatcher) {
-  if (g_notification_manager_tls.Pointer()->Get())
-    return g_notification_manager_tls.Pointer()->Get();
-
-  NotificationManager* manager =
-      new NotificationManager(thread_safe_sender, notification_dispatcher);
-  if (NotificationWorkerId())
-    WorkerThread::AddObserver(manager);
-  return manager;
-}
-
-void NotificationManager::WillStopCurrentWorkerThread() {
-  delete this;
-}
-
-void NotificationManager::ShowPersistent(
-    const blink::WebSecurityOrigin& origin,
-    const blink::WebNotificationData& notification_data,
-    std::unique_ptr<blink::WebNotificationResources> notification_resources,
-    blink::WebServiceWorkerRegistration* service_worker_registration,
-    std::unique_ptr<blink::WebNotificationShowCallbacks> callbacks) {
-  DCHECK(service_worker_registration);
-  DCHECK_EQ(notification_data.actions.size(),
-            notification_resources->action_icons.size());
-
-  int64_t service_worker_registration_id =
-      static_cast<WebServiceWorkerRegistrationImpl*>(
-          service_worker_registration)
-          ->RegistrationId();
-
-  // Verify that the author-provided payload size does not exceed our limit.
-  // This is an implementation-defined limit to prevent abuse of notification
-  // data as a storage mechanism. A UMA histogram records the requested sizes,
-  // which enables us to track how much data authors are attempting to store.
-  //
-  // If the size exceeds this limit, reject the showNotification() promise. This
-  // is outside of the boundaries set by the specification, but it gives authors
-  // an indication that something has gone wrong.
-  size_t author_data_size = notification_data.data.size();
-
-  UMA_HISTOGRAM_COUNTS_1000("Notifications.AuthorDataSize", author_data_size);
-
-  if (author_data_size >
-      blink::mojom::NotificationData::kMaximumDeveloperDataSize) {
-    callbacks->OnError();
-    return;
-  }
-
-  int request_id = notification_dispatcher_->GenerateNotificationRequestId(
-      NotificationWorkerId());
-
-  pending_show_notification_requests_.AddWithID(std::move(callbacks),
-                                                request_id);
-
-  // TODO(mkwst): This is potentially doing the wrong thing with unique
-  // origins. Perhaps also 'file:', 'blob:' and 'filesystem:'. See
-  // https://crbug.com/490074 for detail.
-  thread_safe_sender_->Send(new PlatformNotificationHostMsg_ShowPersistent(
-      request_id, service_worker_registration_id, url::Origin(origin).GetURL(),
-      ToPlatformNotificationData(notification_data),
-      ToNotificationResources(std::move(notification_resources))));
-}
-
-void NotificationManager::GetNotifications(
-    const blink::WebString& filter_tag,
-    blink::WebServiceWorkerRegistration* service_worker_registration,
-    std::unique_ptr<blink::WebNotificationGetCallbacks> callbacks) {
-  DCHECK(service_worker_registration);
-  DCHECK(callbacks);
-
-  WebServiceWorkerRegistrationImpl* service_worker_registration_impl =
-      static_cast<WebServiceWorkerRegistrationImpl*>(
-          service_worker_registration);
-
-  GURL origin = GURL(service_worker_registration_impl->Scope()).GetOrigin();
-  int64_t service_worker_registration_id =
-      service_worker_registration_impl->RegistrationId();
-
-  int request_id = notification_dispatcher_->GenerateNotificationRequestId(
-      NotificationWorkerId());
-
-  pending_get_notification_requests_.AddWithID(std::move(callbacks),
-                                               request_id);
-
-  thread_safe_sender_->Send(new PlatformNotificationHostMsg_GetNotifications(
-      request_id, service_worker_registration_id, origin,
-      filter_tag.Utf8(
-          WebString::UTF8ConversionMode::kStrictReplacingErrorsWithFFFD)));
-}
-
-void NotificationManager::ClosePersistent(
-    const blink::WebSecurityOrigin& origin,
-    const blink::WebString& tag,
-    const blink::WebString& notification_id) {
-  thread_safe_sender_->Send(new PlatformNotificationHostMsg_ClosePersistent(
-      // TODO(mkwst): This is potentially doing the wrong thing with unique
-      // origins. Perhaps also 'file:', 'blob:' and 'filesystem:'. See
-      // https://crbug.com/490074 for detail.
-      url::Origin(origin).GetURL(),
-      tag.Utf8(WebString::UTF8ConversionMode::kStrictReplacingErrorsWithFFFD),
-      notification_id.Utf8(
-          WebString::UTF8ConversionMode::kStrictReplacingErrorsWithFFFD)));
-}
-
-bool NotificationManager::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(NotificationManager, message)
-    IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidShowPersistent,
-                        OnDidShowPersistent)
-    IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidGetNotifications,
-                        OnDidGetNotifications)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-
-  return handled;
-}
-
-void NotificationManager::OnDidShowPersistent(int request_id, bool success) {
-  blink::WebNotificationShowCallbacks* callbacks =
-      pending_show_notification_requests_.Lookup(request_id);
-  DCHECK(callbacks);
-
-  if (!callbacks)
-    return;
-
-  if (success)
-    callbacks->OnSuccess();
-  else
-    callbacks->OnError();
-
-  pending_show_notification_requests_.Remove(request_id);
-}
-
-void NotificationManager::OnDidGetNotifications(
-    int request_id,
-    const std::vector<PersistentNotificationInfo>& notification_infos) {
-  blink::WebNotificationGetCallbacks* callbacks =
-      pending_get_notification_requests_.Lookup(request_id);
-  DCHECK(callbacks);
-  if (!callbacks)
-    return;
-
-  blink::WebVector<blink::WebPersistentNotificationInfo> notifications(
-      notification_infos.size());
-
-  for (size_t i = 0; i < notification_infos.size(); ++i) {
-    blink::WebPersistentNotificationInfo web_notification_info;
-    web_notification_info.notification_id =
-        blink::WebString::FromUTF8(notification_infos[i].first);
-    web_notification_info.data =
-        ToWebNotificationData(notification_infos[i].second);
-
-    notifications[i] = web_notification_info;
-  }
-
-  callbacks->OnSuccess(notifications);
-
-  pending_get_notification_requests_.Remove(request_id);
-}
-
-}  // namespace content
diff --git a/content/renderer/notifications/notification_manager.h b/content/renderer/notifications/notification_manager.h
deleted file mode 100644
index 72190e3f..0000000
--- a/content/renderer/notifications/notification_manager.h
+++ /dev/null
@@ -1,84 +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 CONTENT_RENDERER_NOTIFICATIONS_NOTIFICATION_MANAGER_H_
-#define CONTENT_RENDERER_NOTIFICATIONS_NOTIFICATION_MANAGER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <set>
-#include <vector>
-
-#include "base/containers/id_map.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "content/common/platform_notification_messages.h"
-#include "content/public/renderer/worker_thread.h"
-#include "content/renderer/notifications/notification_dispatcher.h"
-#include "third_party/blink/public/platform/modules/notifications/web_notification_manager.h"
-
-namespace content {
-
-class ThreadSafeSender;
-
-class NotificationManager : public blink::WebNotificationManager,
-                            public WorkerThread::Observer {
- public:
-  ~NotificationManager() override;
-
-  // |thread_safe_sender| and |notification_dispatcher| are used if
-  // calling this leads to construction.
-  static NotificationManager* ThreadSpecificInstance(
-      ThreadSafeSender* thread_safe_sender,
-      NotificationDispatcher* notification_dispatcher);
-
-  // WorkerThread::Observer implementation.
-  void WillStopCurrentWorkerThread() override;
-
-  void ShowPersistent(
-      const blink::WebSecurityOrigin& origin,
-      const blink::WebNotificationData& notification_data,
-      std::unique_ptr<blink::WebNotificationResources> notification_resources,
-      blink::WebServiceWorkerRegistration* service_worker_registration,
-      std::unique_ptr<blink::WebNotificationShowCallbacks> callbacks) override;
-  void GetNotifications(
-      const blink::WebString& filter_tag,
-      blink::WebServiceWorkerRegistration* service_worker_registration,
-      std::unique_ptr<blink::WebNotificationGetCallbacks> callbacks) override;
-  void ClosePersistent(const blink::WebSecurityOrigin& origin,
-                       const blink::WebString& tag,
-                       const blink::WebString& notification_id) override;
-
-  // Called by the NotificationDispatcher.
-  bool OnMessageReceived(const IPC::Message& message);
-
- private:
-  NotificationManager(ThreadSafeSender* thread_safe_sender,
-                      NotificationDispatcher* notification_dispatcher);
-
-  // IPC message handlers.
-  void OnDidShowPersistent(int request_id, bool success);
-  void OnDidGetNotifications(
-      int request_id,
-      const std::vector<PersistentNotificationInfo>& notification_infos);
-
-  scoped_refptr<ThreadSafeSender> thread_safe_sender_;
-  scoped_refptr<NotificationDispatcher> notification_dispatcher_;
-
-  // Tracks pending requests for getting a list of notifications.
-  base::IDMap<std::unique_ptr<blink::WebNotificationGetCallbacks>>
-      pending_get_notification_requests_;
-
-  // Tracks pending requests for displaying persistent notifications.
-  base::IDMap<std::unique_ptr<blink::WebNotificationShowCallbacks>>
-      pending_show_notification_requests_;
-
-  DISALLOW_COPY_AND_ASSIGN(NotificationManager);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_NOTIFICATIONS_NOTIFICATION_MANAGER_H_
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index e66b001..3f687911 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -3357,23 +3357,11 @@
       container_host_ptr_info = provider_context->CloneContainerHostPtrInfo();
   }
 
-  RenderThreadImpl* render_thread = RenderThreadImpl::current();
-  std::unique_ptr<network::SharedURLLoaderFactoryInfo>
-      direct_network_loader_factory_info;
-  // Could be null in tests.
-  if (render_thread) {
-    direct_network_loader_factory_info =
-        base::MakeRefCounted<PossiblyAssociatedWrapperSharedURLLoaderFactory>(
-            render_thread->blink_platform_impl()
-                ->CreateNetworkURLLoaderFactory())
-            ->Clone();
-  }
-
   std::unique_ptr<WorkerFetchContextImpl> worker_fetch_context =
       std::make_unique<WorkerFetchContextImpl>(
           std::move(service_worker_client_request),
           std::move(container_host_ptr_info), GetLoaderFactoryBundle()->Clone(),
-          std::move(direct_network_loader_factory_info),
+          GetLoaderFactoryBundle()->CloneWithoutDefaultFactory(),
           GetContentClient()->renderer()->CreateURLLoaderThrottleProvider(
               URLLoaderThrottleProviderType::kWorker),
           GetContentClient()
@@ -3893,19 +3881,14 @@
   if (document_loader->GetServiceWorkerNetworkProvider())
     return;
 
-  RenderThreadImpl* render_thread = RenderThreadImpl::current();
-  scoped_refptr<network::SharedURLLoaderFactory> direct_network_loader_factory;
-  if (render_thread) {
-    direct_network_loader_factory =
-        base::MakeRefCounted<PossiblyAssociatedWrapperSharedURLLoaderFactory>(
-            render_thread->blink_platform_impl()
-                ->CreateNetworkURLLoaderFactory());
-  }
+  scoped_refptr<network::SharedURLLoaderFactory> fallback_factory =
+      network::SharedURLLoaderFactory::Create(
+          GetLoaderFactoryBundle()->CloneWithoutDefaultFactory());
   document_loader->SetServiceWorkerNetworkProvider(
       ServiceWorkerNetworkProvider::CreateForNavigation(
           routing_id_, navigation_state->request_params(), frame_,
           content_initiated, std::move(controller_service_worker_info_),
-          std::move(direct_network_loader_factory)));
+          std::move(fallback_factory)));
 }
 
 void RenderFrameImpl::DidStartProvisionalLoad(
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 5caeefcac..00be3e3 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -104,7 +104,6 @@
 #include "content/renderer/mus/render_widget_window_tree_client_factory.h"
 #include "content/renderer/mus/renderer_window_tree_client.h"
 #include "content/renderer/net_info_helper.h"
-#include "content/renderer/notifications/notification_dispatcher.h"
 #include "content/renderer/render_frame_proxy.h"
 #include "content/renderer/render_process_impl.h"
 #include "content/renderer/render_view_impl.h"
@@ -803,10 +802,6 @@
                              : mojom::kBrowserServiceName,
                          GetIOTaskRunner());
 
-  notification_dispatcher_ = new NotificationDispatcher(
-      thread_safe_sender(), GetWebMainThreadScheduler()->IPCTaskRunner());
-  AddFilter(notification_dispatcher_->GetFilter());
-
   resource_dispatcher_.reset(new ResourceDispatcher());
   url_loader_throttle_provider_ =
       GetContentClient()->renderer()->CreateURLLoaderThrottleProvider(
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 8f1c03f..0430fdd8 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -138,7 +138,6 @@
 class GpuVideoAcceleratorFactoriesImpl;
 class IndexedDBDispatcher;
 class MidiMessageFilter;
-class NotificationDispatcher;
 class P2PSocketDispatcher;
 class PeerConnectionDependencyFactory;
 class PeerConnectionTracker;
@@ -377,10 +376,6 @@
     return vc_manager_.get();
   }
 
-  NotificationDispatcher* notification_dispatcher() const {
-    return notification_dispatcher_.get();
-  }
-
   mojom::RenderFrameMessageFilter* render_frame_message_filter();
   mojom::RenderMessageFilter* render_message_filter();
 
@@ -655,8 +650,6 @@
   // Used on the render thread.
   std::unique_ptr<VideoCaptureImplManager> vc_manager_;
 
-  scoped_refptr<NotificationDispatcher> notification_dispatcher_;
-
   // The count of RenderWidgets running through this thread.
   int widget_count_;
 
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 23d5d95..1007db7 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -67,8 +67,6 @@
 #include "content/renderer/media_capture_from_element/html_video_element_capturer_source.h"
 #include "content/renderer/media_recorder/media_recorder_handler.h"
 #include "content/renderer/mojo/blink_interface_provider_impl.h"
-#include "content/renderer/notifications/notification_dispatcher.h"
-#include "content/renderer/notifications/notification_manager.h"
 #include "content/renderer/push_messaging/push_provider.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/storage_util.h"
@@ -295,8 +293,6 @@
     web_idb_factory_.reset(new WebIDBFactoryImpl(
         sync_message_filter_,
         RenderThreadImpl::current()->GetIOTaskRunner().get()));
-    notification_dispatcher_ =
-        RenderThreadImpl::current()->notification_dispatcher();
   } else {
     service_manager::mojom::ConnectorRequest request;
     connector_ = service_manager::Connector::Create(&request);
@@ -1294,18 +1290,6 @@
 
 //------------------------------------------------------------------------------
 
-blink::WebNotificationManager*
-RendererBlinkPlatformImpl::GetWebNotificationManager() {
-  if (!thread_safe_sender_.get() || !notification_dispatcher_.get())
-    return nullptr;
-
-  return NotificationManager::ThreadSpecificInstance(
-      thread_safe_sender_.get(),
-      notification_dispatcher_.get());
-}
-
-//------------------------------------------------------------------------------
-
 void RendererBlinkPlatformImpl::DidStartWorkerThread() {
   WorkerThreadRegistry::Instance()->DidStartCurrentWorkerThread();
 }
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 43df197..e604df8e 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -58,7 +58,6 @@
 class BlinkInterfaceProviderImpl;
 class ChildURLLoaderFactoryBundle;
 class LocalStorageCachedAreas;
-class NotificationDispatcher;
 class PlatformEventObserverBase;
 class ThreadSafeSender;
 class WebDatabaseObserverImpl;
@@ -206,7 +205,6 @@
                     const blink::WebString& sample) override;
   void RecordRapporURL(const char* metric, const blink::WebURL& url) override;
   blink::WebPushProvider* PushProvider() override;
-  blink::WebNotificationManager* GetWebNotificationManager() override;
   void DidStartWorkerThread() override;
   void WillStopWorkerThread() override;
   void WorkerContextCreated(const v8::Local<v8::Context>& worker) override;
@@ -333,8 +331,6 @@
   blink::mojom::WebDatabaseHostPtrInfo web_database_host_info_;
   scoped_refptr<blink::mojom::ThreadSafeWebDatabaseHostPtr> web_database_host_;
 
-  scoped_refptr<NotificationDispatcher> notification_dispatcher_;
-
   THREAD_CHECKER(main_thread_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(RendererBlinkPlatformImpl);
diff --git a/content/renderer/service_worker/service_worker_network_provider.cc b/content/renderer/service_worker/service_worker_network_provider.cc
index a29e367..d1d3b2b 100644
--- a/content/renderer/service_worker/service_worker_network_provider.cc
+++ b/content/renderer/service_worker/service_worker_network_provider.cc
@@ -11,6 +11,7 @@
 #include "content/common/service_worker/service_worker_provider_host_info.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/common/browser_side_navigation_policy.h"
+#include "content/public/common/origin_util.h"
 #include "content/renderer/loader/request_extra_data.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/renderer_blink_platform_impl.h"
@@ -111,8 +112,14 @@
         !provider_->context()->GetSubresourceLoaderFactory())
       return nullptr;
 
-    // If it's not for HTTP or HTTPS, no need to intercept the request.
-    if (!GURL(request.Url()).SchemeIsHTTPOrHTTPS())
+    // If the URL is not http(s) or otherwise whitelisted, do not intercept the
+    // request. Schemes like 'blob' and 'file' are not eligible to be
+    // intercepted by service workers.
+    // TODO(falken): Let ServiceWorkerSubresourceLoaderFactory handle the
+    // request and move this check there (i.e., for such URLs, it should use
+    // its fallback factory).
+    const GURL gurl(request.Url());
+    if (!gurl.SchemeIsHTTPOrHTTPS() && !OriginCanAccessServiceWorkers(gurl))
       return nullptr;
 
     // If GetSkipServiceWorker() returns true, do not intercept the request.
@@ -144,7 +151,7 @@
     blink::WebLocalFrame* frame,
     bool content_initiated,
     mojom::ControllerServiceWorkerInfoPtr controller_info,
-    scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory) {
+    scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory) {
   // Determine if a ServiceWorkerNetworkProvider should be created and properly
   // initialized for the navigation. A default ServiceWorkerNetworkProvider
   // will always be created since it is expected in a certain number of places,
@@ -186,7 +193,7 @@
   auto provider = base::WrapUnique(new ServiceWorkerNetworkProvider(
       route_id, blink::mojom::ServiceWorkerProviderType::kForWindow,
       provider_id, is_parent_frame_secure, std::move(controller_info),
-      std::move(default_loader_factory)));
+      std::move(fallback_loader_factory)));
   return std::make_unique<WebServiceWorkerNetworkProviderForFrame>(
       std::move(provider));
 }
@@ -197,13 +204,13 @@
     mojom::ServiceWorkerProviderInfoForSharedWorkerPtr info,
     network::mojom::URLLoaderFactoryAssociatedPtrInfo
         script_loader_factory_info,
-    scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory) {
+    scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory) {
   // S13nServiceWorker: |info| holds info about the precreated provider host.
   if (info) {
     DCHECK(ServiceWorkerUtils::IsServicificationEnabled());
     return base::WrapUnique(new ServiceWorkerNetworkProvider(
         std::move(info), std::move(script_loader_factory_info),
-        std::move(default_loader_factory)));
+        std::move(fallback_loader_factory)));
   }
 
   return base::WrapUnique(new ServiceWorkerNetworkProvider(
@@ -211,7 +218,7 @@
       blink::mojom::ServiceWorkerProviderType::kForSharedWorker,
       GetNextProviderId(), true /* is_parent_frame_secure */,
       nullptr /* controller_service_worker */,
-      std::move(default_loader_factory)));
+      std::move(fallback_loader_factory)));
 }
 
 // static
@@ -261,7 +268,7 @@
     int provider_id,
     bool is_parent_frame_secure,
     mojom::ControllerServiceWorkerInfoPtr controller_info,
-    scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory) {
+    scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory) {
   DCHECK_NE(provider_id, kInvalidServiceWorkerProviderId);
   DCHECK(provider_type == blink::mojom::ServiceWorkerProviderType::kForWindow ||
          provider_type ==
@@ -282,7 +289,7 @@
     context_ = base::MakeRefCounted<ServiceWorkerProviderContext>(
         provider_id, provider_type, std::move(client_request),
         std::move(host_ptr_info), std::move(controller_info),
-        std::move(default_loader_factory));
+        std::move(fallback_loader_factory));
     ChildThreadImpl::current()->channel()->GetRemoteAssociatedInterface(
         &dispatcher_host_);
     dispatcher_host_->OnProviderCreated(std::move(host_info));
@@ -290,7 +297,7 @@
     context_ = base::MakeRefCounted<ServiceWorkerProviderContext>(
         provider_id, provider_type, std::move(client_request),
         std::move(host_ptr_info), std::move(controller_info),
-        std::move(default_loader_factory));
+        std::move(fallback_loader_factory));
   }
 }
 
@@ -299,13 +306,13 @@
     mojom::ServiceWorkerProviderInfoForSharedWorkerPtr info,
     network::mojom::URLLoaderFactoryAssociatedPtrInfo
         script_loader_factory_info,
-    scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory) {
+    scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory) {
   ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance();
   context_ = base::MakeRefCounted<ServiceWorkerProviderContext>(
       info->provider_id,
       blink::mojom::ServiceWorkerProviderType::kForSharedWorker,
       std::move(info->client_request), std::move(info->host_ptr_info),
-      nullptr /* controller */, std::move(default_loader_factory));
+      nullptr /* controller */, std::move(fallback_loader_factory));
   if (script_loader_factory_info.is_valid())
     script_loader_factory_.Bind(std::move(script_loader_factory_info));
 }
diff --git a/content/renderer/service_worker/service_worker_network_provider.h b/content/renderer/service_worker/service_worker_network_provider.h
index 35e76fb..120b71c 100644
--- a/content/renderer/service_worker/service_worker_network_provider.h
+++ b/content/renderer/service_worker/service_worker_network_provider.h
@@ -63,10 +63,10 @@
   // For S13nServiceWorker:
   // |controller_info| contains the endpoint and object info that is needed to
   // set up the controller service worker for the client.
-  // |default_loader_factory| is a default loader factory for network requests,
-  // and is used when we create a subresource loader for controllees. This is
-  // non-null only if the provider is created for controllees, and if the
-  // loading context, e.g. a frame, provides it.
+  // |fallback_loader_factory| is a default loader factory for fallback
+  // requests, and is used when we create a subresource loader for controllees.
+  // This is non-null only if the provider is created for controllees, and if
+  // the loading context, e.g. a frame, provides it.
   static std::unique_ptr<blink::WebServiceWorkerNetworkProvider>
   CreateForNavigation(
       int route_id,
@@ -74,7 +74,7 @@
       blink::WebLocalFrame* frame,
       bool content_initiated,
       mojom::ControllerServiceWorkerInfoPtr controller_info,
-      scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory);
+      scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory);
 
   // Creates a ServiceWorkerNetworkProvider for a shared worker (as a
   // non-document service worker client).
@@ -82,7 +82,7 @@
       mojom::ServiceWorkerProviderInfoForSharedWorkerPtr info,
       network::mojom::URLLoaderFactoryAssociatedPtrInfo
           script_loader_factory_info,
-      scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory);
+      scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory);
 
   // Creates a ServiceWorkerNetworkProvider for a "controller" (i.e.
   // a service worker execution context).
@@ -116,20 +116,20 @@
   //
   // For S13nServiceWorker:
   // See the comment at CreateForNavigation() for |controller_info| and
-  // |default_loader_factory|.
+  // |fallback_loader_factory|.
   ServiceWorkerNetworkProvider(
       int route_id,
       blink::mojom::ServiceWorkerProviderType type,
       int provider_id,
       bool is_parent_frame_secure,
       mojom::ControllerServiceWorkerInfoPtr controller_info,
-      scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory);
+      scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory);
 
   ServiceWorkerNetworkProvider(
       mojom::ServiceWorkerProviderInfoForSharedWorkerPtr info,
       network::mojom::URLLoaderFactoryAssociatedPtrInfo
           script_loader_factory_info,
-      scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory);
+      scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory);
 
   // This is for controllers, used in CreateForController.
   explicit ServiceWorkerNetworkProvider(
diff --git a/content/renderer/service_worker/service_worker_provider_context.cc b/content/renderer/service_worker/service_worker_provider_context.cc
index 540c040..d00cad1 100644
--- a/content/renderer/service_worker/service_worker_provider_context.cc
+++ b/content/renderer/service_worker/service_worker_provider_context.cc
@@ -36,8 +36,8 @@
 // Holds state for service worker clients.
 struct ServiceWorkerProviderContext::ProviderStateForClient {
   explicit ProviderStateForClient(
-      scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory)
-      : default_loader_factory(std::move(default_loader_factory)) {}
+      scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory)
+      : fallback_loader_factory(std::move(fallback_loader_factory)) {}
   ~ProviderStateForClient() = default;
 
   // |controller| will be set by SetController() and taken by TakeController().
@@ -52,7 +52,7 @@
 
   // S13nServiceWorker:
   // Used when we create |subresource_loader_factory|.
-  scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory;
+  scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory;
 
   // Tracks feature usage for UseCounter.
   std::set<blink::mojom::WebFeature> used_features;
@@ -99,7 +99,7 @@
     mojom::ServiceWorkerContainerAssociatedRequest request,
     mojom::ServiceWorkerContainerHostAssociatedPtrInfo host_ptr_info,
     mojom::ControllerServiceWorkerInfoPtr controller_info,
-    scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory)
+    scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory)
     : provider_type_(provider_type),
       provider_id_(provider_id),
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
@@ -107,7 +107,7 @@
       weak_factory_(this) {
   container_host_.Bind(std::move(host_ptr_info));
   state_for_client_ = std::make_unique<ProviderStateForClient>(
-      std::move(default_loader_factory));
+      std::move(fallback_loader_factory));
 
   // Set up the URL loader factory for sending subresource requests to
   // the controller.
@@ -190,7 +190,7 @@
   DCHECK(ServiceWorkerUtils::IsServicificationEnabled());
   if (!state->subresource_loader_factory) {
     ServiceWorkerSubresourceLoaderFactory::Create(
-        state->controller_connector, state->default_loader_factory,
+        state->controller_connector, state->fallback_loader_factory,
         mojo::MakeRequest(&state->subresource_loader_factory));
   }
   return state->subresource_loader_factory.get();
@@ -413,10 +413,9 @@
 bool ServiceWorkerProviderContext::CanCreateSubresourceLoaderFactory() const {
   // Expected that it is called only for clients.
   DCHECK(state_for_client_);
-  // |state_for_client_->default_loader_factory| could be null
-  // in unit tests.
+  // |state_for_client_->fallback_loader_factory| could be null in unit tests.
   return (ServiceWorkerUtils::IsServicificationEnabled() &&
-          state_for_client_->default_loader_factory);
+          state_for_client_->fallback_loader_factory);
 }
 
 void ServiceWorkerProviderContext::DestructOnMainThread() const {
diff --git a/content/renderer/service_worker/service_worker_provider_context.h b/content/renderer/service_worker/service_worker_provider_context.h
index 1e4e354..1aec2fc 100644
--- a/content/renderer/service_worker/service_worker_provider_context.h
+++ b/content/renderer/service_worker/service_worker_provider_context.h
@@ -69,17 +69,17 @@
   // S13nServiceWorker is enabled) and object info that is needed to set up the
   // controller service worker for the client.
   // For S13nServiceWorker:
-  // |default_loader_factory| is a default loader factory for network requests,
-  // and is used when we create a subresource loader for controllees. This is
-  // non-null only if the provider is created for controllees, and if the
-  // loading context, e.g. a frame, provides it.
+  // |fallback_loader_factory| is a default loader factory for fallback
+  // requests, and is used when we create a subresource loader for controllees.
+  // This is non-null only if the provider is created for controllees, and if
+  // the loading context, e.g. a frame, provides it.
   ServiceWorkerProviderContext(
       int provider_id,
       blink::mojom::ServiceWorkerProviderType provider_type,
       mojom::ServiceWorkerContainerAssociatedRequest request,
       mojom::ServiceWorkerContainerHostAssociatedPtrInfo host_ptr_info,
       mojom::ControllerServiceWorkerInfoPtr controller_info,
-      scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory);
+      scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory);
 
   // Constructor for service worker execution contexts.
   ServiceWorkerProviderContext(
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.cc b/content/renderer/service_worker/service_worker_subresource_loader.cc
index ee59935..cfa8335 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader.cc
@@ -142,7 +142,7 @@
     network::mojom::URLLoaderClientPtr client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
     scoped_refptr<ControllerServiceWorkerConnector> controller_connector,
-    scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory)
+    scoped_refptr<network::SharedURLLoaderFactory> fallback_factory)
     : redirect_limit_(net::URLRequest::kMaxRedirects),
       url_loader_client_(std::move(client)),
       url_loader_binding_(this, std::move(request)),
@@ -154,7 +154,7 @@
       options_(options),
       traffic_annotation_(traffic_annotation),
       resource_request_(resource_request),
-      network_loader_factory_(std::move(network_loader_factory)),
+      fallback_factory_(std::move(fallback_factory)),
       weak_factory_(this) {
   DCHECK(controller_connector_);
   response_head_.request_start = base::TimeTicks::Now();
@@ -214,7 +214,7 @@
         ControllerServiceWorkerConnector::State::kNoController) {
       // The controller was lost after this loader or its loader factory was
       // created.
-      network_loader_factory_->CreateLoaderAndStart(
+      fallback_factory_->CreateLoaderAndStart(
           url_loader_binding_.Unbind(), routing_id_, request_id_, options_,
           resource_request_, std::move(url_loader_client_),
           traffic_annotation_);
@@ -342,8 +342,6 @@
 void ServiceWorkerSubresourceLoader::OnFallback(
     base::Time dispatch_event_time) {
   SettleInflightFetchRequestIfNeeded();
-  DCHECK(network_loader_factory_);
-
   // When the request mode is CORS or CORS-with-forced-preflight and the origin
   // of the request URL is different from the security origin of the document,
   // we can't simply fallback to the network here. It is because the CORS
@@ -372,11 +370,17 @@
                           response_head_.service_worker_ready_time));
   mojo::MakeStrongBinding(std::move(client_impl), mojo::MakeRequest(&client));
 
-  network_loader_factory_->CreateLoaderAndStart(
+  fallback_factory_->CreateLoaderAndStart(
       url_loader_binding_.Unbind(), routing_id_, request_id_, options_,
       resource_request_, std::move(client), traffic_annotation_);
   // Per spec, redirects after this point are not intercepted by the service
   // worker again (https://crbug.com/517364). So this loader is done.
+  //
+  // Assume ServiceWorkerSubresourceLoaderFactory is still alive and also
+  // has a ref to fallback_factory_, so it's OK to destruct here. If that
+  // factory dies, the web context that made the request is dead so the request
+  // is moot.
+  DCHECK(!fallback_factory_->HasOneRef());
   delete this;
 }
 
@@ -518,20 +522,20 @@
 // static
 void ServiceWorkerSubresourceLoaderFactory::Create(
     scoped_refptr<ControllerServiceWorkerConnector> controller_connector,
-    scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory,
+    scoped_refptr<network::SharedURLLoaderFactory> fallback_factory,
     network::mojom::URLLoaderFactoryRequest request) {
   new ServiceWorkerSubresourceLoaderFactory(std::move(controller_connector),
-                                            std::move(network_loader_factory),
+                                            std::move(fallback_factory),
                                             std::move(request));
 }
 
 ServiceWorkerSubresourceLoaderFactory::ServiceWorkerSubresourceLoaderFactory(
     scoped_refptr<ControllerServiceWorkerConnector> controller_connector,
-    scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory,
+    scoped_refptr<network::SharedURLLoaderFactory> fallback_factory,
     network::mojom::URLLoaderFactoryRequest request)
     : controller_connector_(std::move(controller_connector)),
-      network_loader_factory_(std::move(network_loader_factory)) {
-  DCHECK(network_loader_factory_);
+      fallback_factory_(std::move(fallback_factory)) {
+  DCHECK(fallback_factory_);
   bindings_.AddBinding(this, std::move(request));
   bindings_.set_connection_error_handler(base::BindRepeating(
       &ServiceWorkerSubresourceLoaderFactory::OnConnectionError,
@@ -551,12 +555,12 @@
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
   // This loader destructs itself, as we want to transparently switch to the
   // network loader when fallback happens. When that happens the loader unbinds
-  // the request, passes the request to the Network Loader Factory, and
+  // the request, passes the request to the fallback factory, and
   // destructs itself (while the loader client continues to work).
-  new ServiceWorkerSubresourceLoader(
-      std::move(request), routing_id, request_id, options, resource_request,
-      std::move(client), traffic_annotation, controller_connector_,
-      network_loader_factory_);
+  new ServiceWorkerSubresourceLoader(std::move(request), routing_id, request_id,
+                                     options, resource_request,
+                                     std::move(client), traffic_annotation,
+                                     controller_connector_, fallback_factory_);
 }
 
 void ServiceWorkerSubresourceLoaderFactory::Clone(
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.h b/content/renderer/service_worker/service_worker_subresource_loader.h
index c232636..c1dbcf7 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.h
+++ b/content/renderer/service_worker/service_worker_subresource_loader.h
@@ -51,7 +51,7 @@
       network::mojom::URLLoaderClientPtr client,
       const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
       scoped_refptr<ControllerServiceWorkerConnector> controller_connector,
-      scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory);
+      scoped_refptr<network::SharedURLLoaderFactory> fallback_factory);
 
   ~ServiceWorkerSubresourceLoader() override;
 
@@ -138,7 +138,7 @@
   std::unique_ptr<StreamWaiter> stream_waiter_;
 
   // For network fallback.
-  scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory> fallback_factory_;
 
   enum class Status {
     kNotStarted,
@@ -168,7 +168,7 @@
   // any custom URLLoader factories.
   static void Create(
       scoped_refptr<ControllerServiceWorkerConnector> controller_connector,
-      scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory,
+      scoped_refptr<network::SharedURLLoaderFactory> fallback_factory,
       network::mojom::URLLoaderFactoryRequest request);
 
   ~ServiceWorkerSubresourceLoaderFactory() override;
@@ -187,16 +187,15 @@
  private:
   ServiceWorkerSubresourceLoaderFactory(
       scoped_refptr<ControllerServiceWorkerConnector> controller_connector,
-      scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory,
+      scoped_refptr<network::SharedURLLoaderFactory> fallback_factory,
       network::mojom::URLLoaderFactoryRequest request);
 
   void OnConnectionError();
 
   scoped_refptr<ControllerServiceWorkerConnector> controller_connector_;
 
-  // A URLLoaderFactory that directly goes to network, used when a request
-  // falls back to network.
-  scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory_;
+  // Used when a request falls back to network.
+  scoped_refptr<network::SharedURLLoaderFactory> fallback_factory_;
 
   mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
 
diff --git a/content/renderer/service_worker/worker_fetch_context_impl.cc b/content/renderer/service_worker/worker_fetch_context_impl.cc
index 358fa659..fa99c3be 100644
--- a/content/renderer/service_worker/worker_fetch_context_impl.cc
+++ b/content/renderer/service_worker/worker_fetch_context_impl.cc
@@ -109,10 +109,8 @@
 WorkerFetchContextImpl::WorkerFetchContextImpl(
     mojom::ServiceWorkerWorkerClientRequest service_worker_client_request,
     mojom::ServiceWorkerContainerHostPtrInfo service_worker_container_host_info,
-    std::unique_ptr<network::SharedURLLoaderFactoryInfo>
-        url_loader_factory_info,
-    std::unique_ptr<network::SharedURLLoaderFactoryInfo>
-        direct_network_factory_info,
+    std::unique_ptr<network::SharedURLLoaderFactoryInfo> loader_factory_info,
+    std::unique_ptr<network::SharedURLLoaderFactoryInfo> fallback_factory_info,
     std::unique_ptr<URLLoaderThrottleProvider> throttle_provider,
     std::unique_ptr<WebSocketHandshakeThrottleProvider>
         websocket_handshake_throttle_provider,
@@ -121,9 +119,8 @@
       service_worker_client_request_(std::move(service_worker_client_request)),
       service_worker_container_host_info_(
           std::move(service_worker_container_host_info)),
-      url_loader_factory_info_(std::move(url_loader_factory_info)),
-      direct_network_loader_factory_info_(
-          std::move(direct_network_factory_info)),
+      loader_factory_info_(std::move(loader_factory_info)),
+      fallback_factory_info_(std::move(fallback_factory_info)),
       thread_safe_sender_(thread_safe_sender),
       throttle_provider_(std::move(throttle_provider)),
       websocket_handshake_throttle_provider_(
@@ -151,9 +148,8 @@
   // behavior. See https://crbug.com/731604
   auto new_context = std::make_unique<WorkerFetchContextImpl>(
       mojom::ServiceWorkerWorkerClientRequest(),
-      mojom::ServiceWorkerContainerHostPtrInfo(),
-      shared_url_loader_factory_->Clone(),
-      direct_network_loader_factory_->Clone(),
+      mojom::ServiceWorkerContainerHostPtrInfo(), loader_factory_->Clone(),
+      fallback_factory_->Clone(),
       throttle_provider_ ? throttle_provider_->Clone() : nullptr,
       websocket_handshake_throttle_provider_
           ? websocket_handshake_throttle_provider_->Clone()
@@ -171,10 +167,10 @@
   resource_dispatcher_->set_terminate_sync_load_event(
       terminate_sync_load_event_);
 
-  shared_url_loader_factory_ = network::SharedURLLoaderFactory::Create(
-      std::move(url_loader_factory_info_));
-  direct_network_loader_factory_ = network::SharedURLLoaderFactory::Create(
-      std::move(direct_network_loader_factory_info_));
+  loader_factory_ =
+      network::SharedURLLoaderFactory::Create(std::move(loader_factory_info_));
+  fallback_factory_ = network::SharedURLLoaderFactory::Create(
+      std::move(fallback_factory_info_));
   if (service_worker_client_request_.is_pending())
     binding_.Bind(std::move(service_worker_client_request_));
 
@@ -192,10 +188,10 @@
 
 std::unique_ptr<blink::WebURLLoaderFactory>
 WorkerFetchContextImpl::CreateURLLoaderFactory() {
-  DCHECK(shared_url_loader_factory_);
+  DCHECK(loader_factory_);
   DCHECK(!url_loader_factory_);
   auto factory = std::make_unique<URLLoaderFactoryImpl>(
-      resource_dispatcher_->GetWeakPtr(), shared_url_loader_factory_);
+      resource_dispatcher_->GetWeakPtr(), loader_factory_);
   url_loader_factory_ = factory->GetWeakPtr();
 
   if (ServiceWorkerUtils::IsServicificationEnabled())
@@ -344,12 +340,12 @@
     url_loader_factory_->SetServiceWorkerURLLoaderFactory(nullptr);
     return;
   }
+
   network::mojom::URLLoaderFactoryPtr service_worker_url_loader_factory;
   ServiceWorkerSubresourceLoaderFactory::Create(
       base::MakeRefCounted<ControllerServiceWorkerConnector>(
           service_worker_container_host_.get()),
-      direct_network_loader_factory_,
-      mojo::MakeRequest(&service_worker_url_loader_factory));
+      fallback_factory_, mojo::MakeRequest(&service_worker_url_loader_factory));
   url_loader_factory_->SetServiceWorkerURLLoaderFactory(
       std::move(service_worker_url_loader_factory));
 }
diff --git a/content/renderer/service_worker/worker_fetch_context_impl.h b/content/renderer/service_worker/worker_fetch_context_impl.h
index 869f539..67014dc8 100644
--- a/content/renderer/service_worker/worker_fetch_context_impl.h
+++ b/content/renderer/service_worker/worker_fetch_context_impl.h
@@ -37,21 +37,27 @@
     : public blink::WebWorkerFetchContext,
       public mojom::ServiceWorkerWorkerClient {
  public:
-  // |url_loader_factory_info| is a generic URLLoaderFactory that may
-  // contain multiple URLLoader factories for different schemes internally,
-  // and used for regular resource loading from the worker context.
-  // |direct_network_factory_info| is a URLLoader factory that directly
-  // goes to the network, used when this context creates a
-  // ServiceWorkerSubresourceLoader because it is controlled by a service
-  // worker.
+  // |loader_factory_info| is used for regular loading by the worker.
+  //
+  // S13nServiceWorker:
+  // If the worker is controlled by a service worker, this class makes another
+  // loader factory which sends requests to the service worker, and passes
+  // |fallback_factory_info| to that factory to use for network fallback.
+  //
+  // |loader_factory_info| and |fallback_factory_info| are different because
+  // |loader_factory_info| can possibly include a default factory like AppCache,
+  // while |fallback_factory_info| should not have such a default factory and
+  // instead go directly to network for http(s) requests.
+  // |fallback_factory_info| might not be simply the direct network factory,
+  // because it might additionally support non-NetworkService schemes (e.g.,
+  // chrome-extension://).
   WorkerFetchContextImpl(
       mojom::ServiceWorkerWorkerClientRequest service_worker_client_request,
       mojom::ServiceWorkerContainerHostPtrInfo
           service_worker_container_host_info,
+      std::unique_ptr<network::SharedURLLoaderFactoryInfo> loader_factory_info,
       std::unique_ptr<network::SharedURLLoaderFactoryInfo>
-          url_loader_factory_info,
-      std::unique_ptr<network::SharedURLLoaderFactoryInfo>
-          direct_network_factory_info,
+          fallback_factory_info,
       std::unique_ptr<URLLoaderThrottleProvider> throttle_provider,
       std::unique_ptr<WebSocketHandshakeThrottleProvider>
           websocket_handshake_throttle_provider,
@@ -118,11 +124,10 @@
   mojom::ServiceWorkerWorkerClientRequest service_worker_client_request_;
   // Consumed on the worker thread to create |service_worker_container_host_|.
   mojom::ServiceWorkerContainerHostPtrInfo service_worker_container_host_info_;
-  // Consumed on the worker thread to create |shared_url_loader_factory_|.
-  std::unique_ptr<network::SharedURLLoaderFactoryInfo> url_loader_factory_info_;
-  // Consumed on the worker thread to create |direct_network_loader_factory_|.
-  std::unique_ptr<network::SharedURLLoaderFactoryInfo>
-      direct_network_loader_factory_info_;
+  // Consumed on the worker thread to create |loader_factory_|.
+  std::unique_ptr<network::SharedURLLoaderFactoryInfo> loader_factory_info_;
+  // Consumed on the worker thread to create |fallback_factory_|.
+  std::unique_ptr<network::SharedURLLoaderFactoryInfo> fallback_factory_info_;
   // Consumed on the worker thread to create |blob_registry_|.
   blink::mojom::BlobRegistryPtrInfo blob_registry_ptr_info_;
 
@@ -136,14 +141,16 @@
   std::unique_ptr<ResourceDispatcher> resource_dispatcher_;
 
   // Initialized on the worker thread when InitializeOnWorkerThread() is called.
-  // |shared_url_loader_factory_| may be a bundled factory that contains
-  // multiple factories for different schemes and to be used for regular
-  // loading by the worker, while |direct_network_loader_factory_| is used
-  // specifically to initialize ServiceWorkerSubresourceLoader for network
-  // load that is controlled by a service worker (when this worker is a
-  // client of the service worker).
-  scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
-  scoped_refptr<network::SharedURLLoaderFactory> direct_network_loader_factory_;
+  // |loader_factory_| is used for regular loading by the worker. In
+  // S13nServiceWorker, if the worker is controlled by a service worker, it
+  // creates a ServiceWorkerSubresourceLoaderFactory instead.
+  scoped_refptr<network::SharedURLLoaderFactory> loader_factory_;
+
+  // Initialized on the worker thread when InitializeOnWorkerThread() is called.
+  // S13nServiceWorker: If the worker is controlled by a service worker, it
+  // passes this factory to ServiceWorkerSubresourceLoaderFactory to use for
+  // network fallback.
+  scoped_refptr<network::SharedURLLoaderFactory> fallback_factory_;
 
   // S13nServiceWorker:
   // Initialized on the worker thread when InitializeOnWorkerThread() is called.
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.cc b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
index 2bde989..e246805f 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.cc
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
@@ -275,20 +275,20 @@
 
 std::unique_ptr<blink::WebServiceWorkerNetworkProvider>
 EmbeddedSharedWorkerStub::CreateServiceWorkerNetworkProvider() {
-  scoped_refptr<network::SharedURLLoaderFactory> direct_network_loader_factory;
+  scoped_refptr<network::SharedURLLoaderFactory> fallback_factory;
   // current() may be null in tests.
   if (RenderThreadImpl* render_thread = RenderThreadImpl::current()) {
-    direct_network_loader_factory =
-        base::MakeRefCounted<PossiblyAssociatedWrapperSharedURLLoaderFactory>(
-            render_thread->blink_platform_impl()
-                ->CreateNetworkURLLoaderFactory());
+    scoped_refptr<ChildURLLoaderFactoryBundle> bundle =
+        render_thread->blink_platform_impl()
+            ->CreateDefaultURLLoaderFactoryBundle();
+    fallback_factory = network::SharedURLLoaderFactory::Create(
+        bundle->CloneWithoutDefaultFactory());
   }
 
   std::unique_ptr<ServiceWorkerNetworkProvider> provider =
       ServiceWorkerNetworkProvider::CreateForSharedWorker(
           std::move(service_worker_provider_info_),
-          std::move(script_loader_factory_info_),
-          std::move(direct_network_loader_factory));
+          std::move(script_loader_factory_info_), std::move(fallback_factory));
   return std::make_unique<WebServiceWorkerNetworkProviderForSharedWorker>(
       std::move(provider), IsOriginSecure(url_));
 }
@@ -329,20 +329,10 @@
       RenderThreadImpl::current()
           ->blink_platform_impl()
           ->CreateDefaultURLLoaderFactoryBundle();
-
-  auto direct_network_loader_factory =
-      base::MakeRefCounted<PossiblyAssociatedWrapperSharedURLLoaderFactory>(
-          RenderThreadImpl::current()
-              ->blink_platform_impl()
-              ->CreateNetworkURLLoaderFactory());
-
-  DCHECK(url_loader_factory_bundle);
-  DCHECK(direct_network_loader_factory);
-
   auto worker_fetch_context = std::make_unique<WorkerFetchContextImpl>(
       std::move(request), std::move(container_host_ptr_info),
       url_loader_factory_bundle->Clone(),
-      direct_network_loader_factory->Clone(),
+      url_loader_factory_bundle->CloneWithoutDefaultFactory(),
       GetContentClient()->renderer()->CreateURLLoaderThrottleProvider(
           URLLoaderThrottleProviderType::kWorker),
       GetContentClient()
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 3e3fc181..6f7a854 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1393,7 +1393,6 @@
     "../browser/payments/payment_manager_unittest.cc",
     "../browser/presentation/presentation_service_impl_unittest.cc",
     "../browser/renderer_host/clipboard_host_impl_unittest.cc",
-    "../browser/renderer_host/compositor_resize_lock_unittest.cc",
     "../browser/renderer_host/cursor_manager_unittest.cc",
     "../browser/renderer_host/dwrite_font_proxy_message_filter_win_unittest.cc",
     "../browser/renderer_host/embedded_frame_sink_provider_impl_unittest.cc",
@@ -1436,6 +1435,7 @@
     "../browser/renderer_host/media/media_stream_ui_proxy_unittest.cc",
     "../browser/renderer_host/media/mock_video_capture_provider.cc",
     "../browser/renderer_host/media/mock_video_capture_provider.h",
+    "../browser/renderer_host/media/old_render_frame_audio_output_stream_factory_unittest.cc",
     "../browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc",
     "../browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc",
     "../browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc",
@@ -1784,6 +1784,7 @@
     "//ppapi/buildflags",
     "//ppapi/c",
     "//printing",
+    "//services/audio/public/cpp:test_support",
     "//services/audio/public/mojom",
     "//services/catalog:lib",
     "//services/device/public/cpp/generic_sensor",
@@ -2031,7 +2032,6 @@
       "../browser/compositor/gpu_vsync_begin_frame_source_unittest.cc",
       "../browser/compositor/reflector_impl_unittest.cc",
       "../browser/compositor/software_browser_compositor_output_surface_unittest.cc",
-      "../browser/renderer_host/compositor_resize_lock_unittest.cc",
     ]
   }
 
diff --git a/extensions/browser/api/cec_private/BUILD.gn b/extensions/browser/api/cec_private/BUILD.gn
index a2e9299..eea3c34 100644
--- a/extensions/browser/api/cec_private/BUILD.gn
+++ b/extensions/browser/api/cec_private/BUILD.gn
@@ -16,4 +16,8 @@
   deps = [
     "//extensions/common/api",
   ]
+
+  public_deps = [
+    "//extensions/browser:browser_sources",
+  ]
 }
diff --git a/extensions/browser/api/cec_private/cec_private_api.cc b/extensions/browser/api/cec_private/cec_private_api.cc
index 63a8b7f0..936a789 100644
--- a/extensions/browser/api/cec_private/cec_private_api.cc
+++ b/extensions/browser/api/cec_private/cec_private_api.cc
@@ -4,19 +4,54 @@
 
 #include "extensions/browser/api/cec_private/cec_private_api.h"
 
+#include <vector>
+
+#include "base/bind.h"
+#include "base/logging.h"
 #include "chromeos/dbus/cec_service_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
+#include "extensions/common/api/cec_private.h"
 #include "extensions/common/manifest_handlers/kiosk_mode_info.h"
 
-namespace extensions {
-
 namespace {
 
 const char kKioskOnlyError[] =
     "Only kiosk enabled extensions are allowed to use this function.";
 
+extensions::api::cec_private::DisplayCecPowerState
+ConvertCecServiceClientPowerState(
+    chromeos::CecServiceClient::PowerState power_state) {
+  switch (power_state) {
+    case chromeos::CecServiceClient::PowerState::kError:
+      return extensions::api::cec_private::DISPLAY_CEC_POWER_STATE_ERROR;
+    case chromeos::CecServiceClient::PowerState::kAdapterNotConfigured:
+      return extensions::api::cec_private::
+          DISPLAY_CEC_POWER_STATE_ADAPTERNOTCONFIGURED;
+    case chromeos::CecServiceClient::PowerState::kNoDevice:
+      return extensions::api::cec_private::DISPLAY_CEC_POWER_STATE_NODEVICE;
+    case chromeos::CecServiceClient::PowerState::kOn:
+      return extensions::api::cec_private::DISPLAY_CEC_POWER_STATE_ON;
+    case chromeos::CecServiceClient::PowerState::kStandBy:
+      return extensions::api::cec_private::DISPLAY_CEC_POWER_STATE_STANDBY;
+    case chromeos::CecServiceClient::PowerState::kTransitioningToOn:
+      return extensions::api::cec_private::
+          DISPLAY_CEC_POWER_STATE_TRANSITIONINGTOON;
+    case chromeos::CecServiceClient::PowerState::kTransitioningToStandBy:
+      return extensions::api::cec_private::
+          DISPLAY_CEC_POWER_STATE_TRANSITIONINGTOSTANDBY;
+    case chromeos::CecServiceClient::PowerState::kUnknown:
+      return extensions::api::cec_private::DISPLAY_CEC_POWER_STATE_UNKNOWN;
+  }
+
+  NOTREACHED();
+  return extensions::api::cec_private::DISPLAY_CEC_POWER_STATE_UNKNOWN;
+}
+
 }  // namespace
 
+namespace extensions {
+namespace api {
+
 CecPrivateFunction::CecPrivateFunction() = default;
 
 CecPrivateFunction::~CecPrivateFunction() = default;
@@ -51,4 +86,33 @@
   return RespondNow(NoArguments());
 }
 
+CecPrivateQueryDisplayCecPowerStateFunction::
+    CecPrivateQueryDisplayCecPowerStateFunction() = default;
+
+CecPrivateQueryDisplayCecPowerStateFunction::
+    ~CecPrivateQueryDisplayCecPowerStateFunction() = default;
+
+ExtensionFunction::ResponseAction
+CecPrivateQueryDisplayCecPowerStateFunction::Run() {
+  chromeos::DBusThreadManager::Get()
+      ->GetCecServiceClient()
+      ->QueryDisplayCecPowerState(base::BindOnce(
+          &CecPrivateQueryDisplayCecPowerStateFunction::HandlePowerStates,
+          this));
+  return RespondLater();
+}
+
+void CecPrivateQueryDisplayCecPowerStateFunction::HandlePowerStates(
+    const std::vector<chromeos::CecServiceClient::PowerState>& power_states) {
+  std::vector<cec_private::DisplayCecPowerState> result_power_states;
+
+  for (const chromeos::CecServiceClient::PowerState& state : power_states) {
+    result_power_states.push_back(ConvertCecServiceClientPowerState(state));
+  }
+
+  Respond(ArgumentList(cec_private::QueryDisplayCecPowerState::Results::Create(
+      result_power_states)));
+}
+
+}  // namespace api
 }  // namespace extensions
diff --git a/extensions/browser/api/cec_private/cec_private_api.h b/extensions/browser/api/cec_private/cec_private_api.h
index a9c15396..6a2029b5 100644
--- a/extensions/browser/api/cec_private/cec_private_api.h
+++ b/extensions/browser/api/cec_private/cec_private_api.h
@@ -5,10 +5,14 @@
 #ifndef EXTENSIONS_BROWSER_API_CEC_PRIVATE_CEC_PRIVATE_API_H_
 #define EXTENSIONS_BROWSER_API_CEC_PRIVATE_CEC_PRIVATE_API_H_
 
+#include <vector>
+
+#include "chromeos/dbus/cec_service_client.h"
 #include "extensions/browser/extension_function.h"
 #include "extensions/browser/extension_function_histogram_value.h"
 
 namespace extensions {
+namespace api {
 
 class CecPrivateFunction : public UIThreadExtensionFunction {
  public:
@@ -48,6 +52,24 @@
   DISALLOW_COPY_AND_ASSIGN(CecPrivateSendWakeUpFunction);
 };
 
+class CecPrivateQueryDisplayCecPowerStateFunction : public CecPrivateFunction {
+ public:
+  CecPrivateQueryDisplayCecPowerStateFunction();
+  DECLARE_EXTENSION_FUNCTION("cecPrivate.queryDisplayCecPowerState",
+                             CECPRIVATE_QUERYDISPLAYCECPOWERSTATE)
+
+ protected:
+  ~CecPrivateQueryDisplayCecPowerStateFunction() override;
+  ResponseAction Run() override;
+
+ private:
+  void HandlePowerStates(
+      const std::vector<chromeos::CecServiceClient::PowerState>& power_states);
+
+  DISALLOW_COPY_AND_ASSIGN(CecPrivateQueryDisplayCecPowerStateFunction);
+};
+
+}  // namespace api
 }  // namespace extensions
 
 #endif  // EXTENSIONS_BROWSER_API_CEC_PRIVATE_CEC_PRIVATE_API_H_
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 1cf7c31..7a4f5a2 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1312,6 +1312,7 @@
   INPUTMETHODPRIVATE_GETCOMPOSITIONBOUNDS,
   FILEMANAGERPRIVATE_ISCROSTINIENABLED,
   FILEMANAGERPRIVATE_MOUNTCROSTINICONTAINER,
+  CECPRIVATE_QUERYDISPLAYCECPOWERSTATE,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/browser/extension_protocols.cc b/extensions/browser/extension_protocols.cc
index 7f1fa0f..c162822d 100644
--- a/extensions/browser/extension_protocols.cc
+++ b/extensions/browser/extension_protocols.cc
@@ -740,23 +740,30 @@
 
 class ExtensionURLLoaderFactory : public network::mojom::URLLoaderFactory {
  public:
-  // |render_process_id| and |render_frame_id| identify the RenderFrameHost
-  // which is either loading a non-subresource (e.g., being navigated or
-  // starting a service worker), or loading a subresource. For non-subresource
-  // requests, |frame_url| is empty; for subresource requests it's the URL of
-  // the currently committed navigation on the frame host.
-  ExtensionURLLoaderFactory(
-      int render_process_id,
-      int render_frame_id,
-      const GURL& frame_url,
-      scoped_refptr<extensions::InfoMap> extension_info_map)
-      : frame_host_(content::RenderFrameHost::FromID(render_process_id,
-                                                     render_frame_id)),
-        process_host_(content::RenderProcessHost::FromID(render_process_id)),
-        frame_url_(frame_url),
-        extension_info_map_(std::move(extension_info_map)) {
+  ExtensionURLLoaderFactory(int render_process_id, int render_frame_id)
+      : render_process_id_(render_process_id) {
+    content::RenderProcessHost* process_host =
+        content::RenderProcessHost::FromID(render_process_id);
+    browser_context_ = process_host->GetBrowserContext();
+    is_web_view_request_ = WebViewGuest::FromFrameID(
+                               render_process_id_, render_frame_id) != nullptr;
+    Init();
+  }
+
+  ExtensionURLLoaderFactory(content::BrowserContext* browser_context,
+                            bool is_web_view_request)
+      : browser_context_(browser_context),
+        is_web_view_request_(is_web_view_request),
+        render_process_id_(-1) {
+    Init();
+  }
+
+  void Init() {
+    extension_info_map_ =
+        extensions::ExtensionSystem::Get(browser_context_)->info_map();
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   }
+
   ~ExtensionURLLoaderFactory() override = default;
 
   // network::mojom::URLLoaderFactory:
@@ -770,22 +777,21 @@
                                 traffic_annotation) override {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     DCHECK(!request.download_to_file);
-    BrowserContext* browser_context = process_host_->GetBrowserContext();
 
     const std::string extension_id = request.url.host();
-    ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context);
+    ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
     scoped_refptr<const Extension> extension =
         registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
     const ExtensionSet& enabled_extensions = registry->enabled_extensions();
-    const ProcessMap* process_map = ProcessMap::Get(browser_context);
+    const ProcessMap* process_map = ProcessMap::Get(browser_context_);
     bool incognito_enabled =
-        extensions::util::IsIncognitoEnabled(extension_id, browser_context);
+        extensions::util::IsIncognitoEnabled(extension_id, browser_context_);
 
     if (!AllowExtensionResourceLoad(
             request.url,
             static_cast<content::ResourceType>(request.resource_type),
             static_cast<ui::PageTransition>(request.transition_type),
-            process_host_->GetID(), browser_context->IsOffTheRecord(),
+            render_process_id_, browser_context_->IsOffTheRecord(),
             extension.get(), incognito_enabled, enabled_extensions,
             *process_map)) {
       client->OnComplete(
@@ -820,13 +826,9 @@
     bool send_cors_header = false;
     bool follow_symlinks_anywhere = false;
     if (extension) {
-      const bool is_web_view_request =
-          WebViewGuest::FromWebContents(
-              content::WebContents::FromRenderFrameHost(frame_host_)) !=
-          nullptr;
-      GetSecurityPolicyForURL(request.url, extension.get(), is_web_view_request,
-                              &content_security_policy, &send_cors_header,
-                              &follow_symlinks_anywhere);
+      GetSecurityPolicyForURL(request.url, extension.get(),
+                              is_web_view_request_, &content_security_policy,
+                              &send_cors_header, &follow_symlinks_anywhere);
     }
 
     if (IsBackgroundPageURL(request.url)) {
@@ -890,8 +892,7 @@
       std::string new_relative_path;
       SharedModuleInfo::ParseImportedPath(path, &new_extension_id,
                                           &new_relative_path);
-      BrowserContext* browser_context = process_host_->GetBrowserContext();
-      ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context);
+      ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
       const Extension* new_extension =
           registry->enabled_extensions().GetByID(new_extension_id);
       if (SharedModuleInfo::ImportsExtensionById(extension.get(),
@@ -975,11 +976,12 @@
         std::move(response_headers));
   }
 
-  // |frame_host_| may be null if, e.g., this request is for loading a service
-  // worker.
-  content::RenderFrameHost* const frame_host_;
-  content::RenderProcessHost* const process_host_;
-  const GURL frame_url_;
+  content::BrowserContext* browser_context_;
+  bool is_web_view_request_;
+  // We store the ID and get RenderProcessHost each time it's needed. This is to
+  // avoid holding on to stale pointers if we get requests past the lifetime of
+  // the objects.
+  const int render_process_id_;
   scoped_refptr<extensions::InfoMap> extension_info_map_;
   mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
 
@@ -1039,29 +1041,16 @@
 
 std::unique_ptr<network::mojom::URLLoaderFactory>
 CreateExtensionNavigationURLLoaderFactory(
-    int render_process_id,
-    int render_frame_id,
-    scoped_refptr<extensions::InfoMap> extension_info_map) {
-  return std::make_unique<ExtensionURLLoaderFactory>(
-      render_process_id, render_frame_id, GURL(),
-      std::move(extension_info_map));
+    content::BrowserContext* browser_context,
+    bool is_web_view_request) {
+  return std::make_unique<ExtensionURLLoaderFactory>(browser_context,
+                                                     is_web_view_request);
 }
 
 std::unique_ptr<network::mojom::URLLoaderFactory>
-MaybeCreateExtensionSubresourceURLLoaderFactory(
-    int render_process_id,
-    int render_frame_id,
-    const GURL& frame_url,
-    scoped_refptr<extensions::InfoMap> extension_info_map) {
-  // TODO(rockot): We can probably avoid creating this factory in cases where
-  // |frame_url| corresponds to a non-extensions URL and the URL in question
-  // cannot have any active content scripts running and has no access to
-  // any extension's web accessible resources. For now we always create a
-  // factory, because the loader itself correctly prevents disallowed resources
-  // from loading in an invalid context.
-  return std::make_unique<ExtensionURLLoaderFactory>(
-      render_process_id, render_frame_id, frame_url,
-      std::move(extension_info_map));
+CreateExtensionURLLoaderFactory(int render_process_id, int render_frame_id) {
+  return std::make_unique<ExtensionURLLoaderFactory>(render_process_id,
+                                                     render_frame_id);
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/extension_protocols.h b/extensions/browser/extension_protocols.h
index edae5e9..1ddcd71d 100644
--- a/extensions/browser/extension_protocols.h
+++ b/extensions/browser/extension_protocols.h
@@ -18,12 +18,14 @@
 class Time;
 }
 
+namespace content {
+class BrowserContext;
+}
+
 namespace net {
 class HttpResponseHeaders;
 }
 
-class GURL;
-
 namespace extensions {
 class InfoMap;
 
@@ -50,29 +52,21 @@
 void SetExtensionProtocolTestHandler(ExtensionProtocolTestHandler* handler);
 
 // Creates a new network::mojom::URLLoaderFactory implementation suitable for
-// handling navigation requests to extension URLs. This function can also be
-// used to make a factory for other non-subresource requests to extension URLs,
-// such as for the service worker script when starting a service worker.
-// |render_process_id| and |render_frame_id| identify the process and frame that
-// the requests are for.  The frame id may be MSG_ROUTING_NONE if there is no
-// frame, e.g., if the factory is for service worker requests.
+// handling navigation requests to extension URLs.
 std::unique_ptr<network::mojom::URLLoaderFactory>
 CreateExtensionNavigationURLLoaderFactory(
-    int render_process_id,
-    int render_frame_id,
-    scoped_refptr<extensions::InfoMap> extension_info_map);
+    content::BrowserContext* browser_context,
+    bool is_web_view_request);
 
-// Attempts to create a network::mojom::URLLoaderFactory implementation suitable
-// for handling subresource requests for extension URLs for the frame identified
-// by |render_process_id| and |render_frame_id|. May return null if that frame
-// is never allowed to load extension subresources from its current navigation
-// URL.
+// Creates a network::mojom::URLLoaderFactory implementation suitable for
+// handling subresource requests for extension URLs for the frame identified by
+// |render_process_id| and |render_frame_id|.
+// This function can also be used to make a factory for other non-subresource
+// requests to extension URLs, such as for the service worker script when
+// starting a service worker. In that case, render_frame_id will be
+// MSG_ROUTING_NONE.
 std::unique_ptr<network::mojom::URLLoaderFactory>
-MaybeCreateExtensionSubresourceURLLoaderFactory(
-    int render_process_id,
-    int render_frame_id,
-    const GURL& frame_url,
-    scoped_refptr<extensions::InfoMap> extension_info_map);
+CreateExtensionURLLoaderFactory(int render_process_id, int render_frame_id);
 
 }  // namespace extensions
 
diff --git a/extensions/common/api/cec_private.idl b/extensions/common/api/cec_private.idl
index 25a0bc8..16585de9 100644
--- a/extensions/common/api/cec_private.idl
+++ b/extensions/common/api/cec_private.idl
@@ -6,8 +6,38 @@
 [platforms=("chromeos")]
 namespace cecPrivate {
 
+  enum DisplayCecPowerState {
+    // There was an error querying the power state of the display.
+    error,
+
+    // The kernel adapter for the CEC endpoint isn’t configured (no EDID set).
+    adapterNotConfigured,
+
+    // No device ACKed the request on the CEC bus.
+    noDevice,
+
+    // The display is a powered on state.
+    on,
+
+    // The display is in standby mode.
+    standby,
+
+    // The display is currently transitioning to an awake state. It can't be
+    // relied on to show any output yet.
+    transitioningToOn,
+
+    // The display is currently transitioning to standby.
+    transitioningToStandby,
+
+    // Found a CEC endpoint but unable to determine the power state.
+    unknown
+  };
+
+  callback DisplayCecPowerStateCallback =
+      void(DisplayCecPowerState[] powerStates);
+
   interface Functions {
-    // Attempt to put all HDMI CEC compatible devices in stand-by.
+    // Attempt to put all HDMI CEC compatible devices in standby.
     //
     // This is not guaranteed to have any effect on the connected displays.
     // Displays that do not support HDMI CEC will not be affected.
@@ -17,5 +47,9 @@
     // HDMI CEC enabled displays connected, waking them from standby if
     // necessary.
     static void sendWakeUp();
+
+    // Queries all HDMI CEC capable displays for their current power state.
+    static void queryDisplayCecPowerState(
+        DisplayCecPowerStateCallback callback);
   };
 };
diff --git a/extensions/shell/browser/shell_content_browser_client.cc b/extensions/shell/browser/shell_content_browser_client.cc
index 62cc188..293a8c09 100644
--- a/extensions/shell/browser/shell_content_browser_client.cc
+++ b/extensions/shell/browser/shell_content_browser_client.cc
@@ -18,6 +18,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/common/content_descriptors.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
@@ -30,6 +31,7 @@
 #include "extensions/browser/extension_protocols.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/guest_view/extensions_guest_view_message_filter.h"
+#include "extensions/browser/guest_view/web_view/web_view_guest.h"
 #include "extensions/browser/info_map.h"
 #include "extensions/browser/io_thread_extension_message_filter.h"
 #include "extensions/browser/process_map.h"
@@ -262,28 +264,23 @@
 }
 
 void ShellContentBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories(
-    int render_process_id,
-    int render_frame_id,
+    int frame_tree_node_id,
     NonNetworkURLLoaderFactoryMap* factories) {
-  content::RenderProcessHost* process_host =
-      content::RenderProcessHost::FromID(render_process_id);
-  content::BrowserContext* browser_context = process_host->GetBrowserContext();
+  content::WebContents* web_contents =
+      content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
   factories->emplace(
       extensions::kExtensionScheme,
       extensions::CreateExtensionNavigationURLLoaderFactory(
-          render_process_id, render_frame_id,
-          extensions::ExtensionSystem::Get(browser_context)->info_map()));
+          web_contents->GetBrowserContext(),
+          !!extensions::WebViewGuest::FromWebContents(web_contents)));
 }
 
 void ShellContentBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
-    content::RenderFrameHost* frame_host,
-    const GURL& frame_url,
+    int render_process_id,
+    int render_frame_id,
     NonNetworkURLLoaderFactoryMap* factories) {
-  content::RenderProcessHost* process_host = frame_host->GetProcess();
-  content::BrowserContext* browser_context = process_host->GetBrowserContext();
-  auto factory = extensions::MaybeCreateExtensionSubresourceURLLoaderFactory(
-      process_host->GetID(), frame_host->GetRoutingID(), frame_url,
-      extensions::ExtensionSystem::Get(browser_context)->info_map());
+  auto factory = extensions::CreateExtensionURLLoaderFactory(render_process_id,
+                                                             render_frame_id);
   if (factory)
     factories->emplace(extensions::kExtensionScheme, std::move(factory));
 }
diff --git a/extensions/shell/browser/shell_content_browser_client.h b/extensions/shell/browser/shell_content_browser_client.h
index 98cabe9..2e33a80 100644
--- a/extensions/shell/browser/shell_content_browser_client.h
+++ b/extensions/shell/browser/shell_content_browser_client.h
@@ -67,12 +67,11 @@
   std::unique_ptr<content::NavigationUIData> GetNavigationUIData(
       content::NavigationHandle* navigation_handle) override;
   void RegisterNonNetworkNavigationURLLoaderFactories(
-      int render_proces_id,
-      int render_frame_id,
+      int frame_tree_node_id,
       NonNetworkURLLoaderFactoryMap* factories) override;
   void RegisterNonNetworkSubresourceURLLoaderFactories(
-      content::RenderFrameHost* frame_host,
-      const GURL& frame_url,
+      int render_process_id,
+      int render_frame_id,
       NonNetworkURLLoaderFactoryMap* factories) override;
   bool WillCreateURLLoaderFactory(
       content::RenderFrameHost* frame_host,
diff --git a/infra/config/global/luci-milo-dev.cfg b/infra/config/global/luci-milo-dev.cfg
index 8497032..518f5677 100644
--- a/infra/config/global/luci-milo-dev.cfg
+++ b/infra/config/global/luci-milo-dev.cfg
@@ -2340,9 +2340,21 @@
     category: "gce"
   }
   builders: {
+    name: "buildbot/chromium.goma/Chromium Linux Goma RBE Staging (clobber)"
+    category: "rbe"
+  }
+  builders: {
     name: "buildbot/chromium.goma/Chromium Linux Goma RBE Staging"
     category: "rbe"
   }
+  builders: {
+    name: "buildbot/chromium.goma/Chromium Linux Goma RBE Staging (dbg) (clobber)"
+    category: "rbe"
+  }
+  builders: {
+    name: "buildbot/chromium.goma/Chromium Linux Goma RBE Staging (dbg)"
+    category: "rbe"
+  }
 }
 
 consoles: {
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 4312f25..65f17d7 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -2604,9 +2604,24 @@
     short_name: "win"
   }
   builders: {
+    name: "buildbot/chromium.goma/Chromium Linux Goma RBE Staging (clobber)"
+    category: "rbe|rel"
+    short_name: "clb"
+  }
+  builders: {
     name: "buildbot/chromium.goma/Chromium Linux Goma RBE Staging"
-    category: "rbe"
-    short_name: "lnx"
+    category: "rbe|rel"
+    short_name: ""
+  }
+  builders: {
+    name: "buildbot/chromium.goma/Chromium Linux Goma RBE Staging (dbg) (clobber)"
+    category: "rbe|debug"
+    short_name: "clb"
+  }
+  builders: {
+    name: "buildbot/chromium.goma/Chromium Linux Goma RBE Staging (dbg)"
+    category: "rbe|debug"
+    short_name: ""
   }
 }
 
diff --git a/ios/chrome/browser/google/google_url_tracker_client_impl.cc b/ios/chrome/browser/google/google_url_tracker_client_impl.cc
index 4b29376..3e9d969 100644
--- a/ios/chrome/browser/google/google_url_tracker_client_impl.cc
+++ b/ios/chrome/browser/google/google_url_tracker_client_impl.cc
@@ -24,6 +24,7 @@
   return browser_state_->GetPrefs();
 }
 
-net::URLRequestContextGetter* GoogleURLTrackerClientImpl::GetRequestContext() {
-  return browser_state_->GetRequestContext();
+network::mojom::URLLoaderFactory*
+GoogleURLTrackerClientImpl::GetURLLoaderFactory() {
+  return browser_state_->GetURLLoaderFactory();
 }
diff --git a/ios/chrome/browser/google/google_url_tracker_client_impl.h b/ios/chrome/browser/google/google_url_tracker_client_impl.h
index fb39b7da..11e0f9c3 100644
--- a/ios/chrome/browser/google/google_url_tracker_client_impl.h
+++ b/ios/chrome/browser/google/google_url_tracker_client_impl.h
@@ -14,10 +14,6 @@
 class ChromeBrowserState;
 }
 
-namespace net {
-class URLRequestContextGetter;
-}
-
 class GoogleURLTrackerClientImpl : public GoogleURLTrackerClient {
  public:
   explicit GoogleURLTrackerClientImpl(ios::ChromeBrowserState* browser_state);
@@ -27,7 +23,7 @@
   // GoogleURLTrackerClient implementation.
   bool IsBackgroundNetworkingEnabled() override;
   PrefService* GetPrefs() override;
-  net::URLRequestContextGetter* GetRequestContext() override;
+  network::mojom::URLLoaderFactory* GetURLLoaderFactory() override;
 
   ios::ChromeBrowserState* browser_state_;
 
diff --git a/ios/chrome/browser/ui/fullscreen/BUILD.gn b/ios/chrome/browser/ui/fullscreen/BUILD.gn
index e27c5622..73bad64 100644
--- a/ios/chrome/browser/ui/fullscreen/BUILD.gn
+++ b/ios/chrome/browser/ui/fullscreen/BUILD.gn
@@ -70,10 +70,6 @@
     "fullscreen_model.h",
     "fullscreen_model.mm",
     "fullscreen_model_observer.h",
-    "fullscreen_scroll_end_animator.h",
-    "fullscreen_scroll_end_animator.mm",
-    "fullscreen_scroll_to_top_animator.h",
-    "fullscreen_scroll_to_top_animator.mm",
     "fullscreen_system_notification_observer.h",
     "fullscreen_system_notification_observer.mm",
     "fullscreen_ui_updater.mm",
@@ -83,8 +79,6 @@
     "fullscreen_web_state_observer.mm",
     "fullscreen_web_view_proxy_observer.h",
     "fullscreen_web_view_proxy_observer.mm",
-    "toolbar_reveal_animator.h",
-    "toolbar_reveal_animator.mm",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_animator.h b/ios/chrome/browser/ui/fullscreen/fullscreen_animator.h
index e18bfcf..14a432f 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_animator.h
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_animator.h
@@ -7,11 +7,19 @@
 
 #import "ios/chrome/browser/ui/util/optional_property_animator.h"
 
+// Enum describing whether the animator should enter or exit fullscreen.
+enum class FullscreenAnimatorStyle : short {
+  ENTER_FULLSCREEN,
+  EXIT_FULLSCREEN
+};
+
 // Helper object for animating changes to fullscreen progress.  Subclasses of
 // this object are provided to FullscreenControllerObservers to coordinate
 // animations across several different ojects.
 @interface FullscreenAnimator : OptionalPropertyAnimator
 
+// The animator style.
+@property(nonatomic, readonly) FullscreenAnimatorStyle style;
 // The progress value at the start of the animation.
 @property(nonatomic, readonly) CGFloat startProgress;
 // The final calculated fullscreen value.
@@ -23,7 +31,7 @@
 
 // Designated initializer.
 - (instancetype)initWithStartProgress:(CGFloat)startProgress
-                             duration:(NSTimeInterval)duration
+                                style:(FullscreenAnimatorStyle)style
     NS_DESIGNATED_INITIALIZER;
 - (instancetype)initWithDuration:(NSTimeInterval)duration
                 timingParameters:(id<UITimingCurveProvider>)parameters
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_animator.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_animator.mm
index 29777d4..97e7bfd 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_animator.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_animator.mm
@@ -25,22 +25,27 @@
 @end
 
 @implementation FullscreenAnimator
+@synthesize style = _style;
 @synthesize startProgress = _startProgress;
-@dynamic finalProgress;
+@synthesize finalProgress = _finalProgress;
 
 - (instancetype)initWithStartProgress:(CGFloat)startProgress
-                             duration:(NSTimeInterval)duration {
+                                style:(FullscreenAnimatorStyle)style {
   // Control points for Material Design CurveEaseOut curve.
   UICubicTimingParameters* timingParams = [[UICubicTimingParameters alloc]
       initWithControlPoint1:CGPointMake(0.0, 0.0)
               controlPoint2:CGPointMake(0.2, 0.1)];
   DCHECK_GE(startProgress, 0.0);
   DCHECK_LE(startProgress, 1.0);
-  self = [super initWithDuration:duration timingParameters:timingParams];
+  self = [super initWithDuration:ios::material::kDuration1
+                timingParameters:timingParams];
   if (self) {
     DCHECK_GE(startProgress, 0.0);
     DCHECK_LE(startProgress, 1.0);
+    _style = style;
     _startProgress = startProgress;
+    _finalProgress =
+        _style == FullscreenAnimatorStyle::ENTER_FULLSCREEN ? 0.0 : 1.0;
     _bezier = std::make_unique<gfx::CubicBezier>(
         timingParams.controlPoint1.x, timingParams.controlPoint1.y,
         timingParams.controlPoint2.x, timingParams.controlPoint2.y);
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h b/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h
index 225c60b7..62cbab34 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h
@@ -10,9 +10,9 @@
 
 #include "base/macros.h"
 #include "base/observer_list.h"
+#import "ios/chrome/browser/ui/fullscreen/fullscreen_animator.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_model_observer.h"
 
-@class FullscreenAnimator;
 class FullscreenController;
 class FullscreenControllerObserver;
 @class FullscreenResetAnimator;
@@ -55,41 +55,24 @@
   void FullscreenModelScrollEventEnded(FullscreenModel* model) override;
   void FullscreenModelWasReset(FullscreenModel* model) override;
 
-  // Sets up |animator|.  |animator| is expected to be a pointer to a data
-  // member of this object, and is used to reset the variable in the animation
-  // completion block.
-  void SetUpAnimator(__strong FullscreenAnimator** animator);
+  // Sets up |animator_| with |style|.
+  void SetUpAnimator(FullscreenAnimatorStyle style);
 
-  // Starts |animator| if it has animations to run.  |animator| is expected to
-  // be a pointer to a data member of this object, and will be reset when
-  // attempting to start an animator without any animation blocks.
-  void StartAnimator(__strong FullscreenAnimator** animator);
+  // Starts |animator+| if it has animations to run.  |animator_| will be reset
+  // if no animations have been added.
+  void StartAnimator();
 
   // Stops the current scroll end animation if one is in progress.  If
   // |update_model| is true, the FullscreenModel will be updated with the active
   // animator's current progress value.
   void StopAnimating(bool update_model);
 
-  // Stops |animator|.  |animator| is expected to be a pointer to a data member
-  // of this object, and is used to reset the variable.  If |update_model| is
-  // true, the FullscreenModel will be updated with the current progress of the
-  // animator before deallocation.
-  void StopAnimator(__strong FullscreenAnimator** animator, bool update_model);
-
-  // Checks whether |animator| is a valid pointer to one of the three animator
-  // data members of this class.  No-op for non-debug builds.
-  void VerifyAnimatorPointer(__strong FullscreenAnimator** animator) const;
-
   // The controller.
   FullscreenController* controller_ = nullptr;
   // The model.
   FullscreenModel* model_ = nullptr;
-  // The scroll end animator passed to observers.
-  __strong FullscreenScrollEndAnimator* scroll_end_animator_ = nil;
-  // The scroll to top animator passed to observers.
-  __strong FullscreenScrollToTopAnimator* scroll_to_top_animator_ = nil;
-  // The toolbar reveal animator.
-  __strong ToolbarRevealAnimator* toolbar_reveal_animator_ = nil;
+  // The active animator.
+  __strong FullscreenAnimator* animator_ = nil;
   // The FullscreenControllerObservers that need to get notified of model
   // changes.
   base::ObserverList<FullscreenControllerObserver> observers_;
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.mm
index 2de7684..2748638 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_mediator.mm
@@ -9,9 +9,6 @@
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_animator.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_observer.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h"
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h"
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_to_top_animator.h"
-#import "ios/chrome/browser/ui/fullscreen/toolbar_reveal_animator.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -33,51 +30,49 @@
 }
 
 void FullscreenMediator::ScrollToTop() {
-  DCHECK(!scroll_to_top_animator_);
-  CGFloat progress = model_->progress();
-  scroll_to_top_animator_ =
-      [[FullscreenScrollToTopAnimator alloc] initWithStartProgress:progress];
-  SetUpAnimator(&scroll_to_top_animator_);
+  FullscreenAnimatorStyle scrollToTopStyle =
+      FullscreenAnimatorStyle::EXIT_FULLSCREEN;
+  if (animator_ && animator_.style == scrollToTopStyle)
+    return;
+  StopAnimating(true);
+
+  SetUpAnimator(scrollToTopStyle);
   for (auto& observer : observers_) {
-    observer.FullscreenWillScrollToTop(controller_, scroll_to_top_animator_);
+    observer.FullscreenWillScrollToTop(controller_, animator_);
   }
-  StartAnimator(&scroll_to_top_animator_);
+  StartAnimator();
 }
 
 void FullscreenMediator::WillEnterForeground() {
-  if (toolbar_reveal_animator_)
+  FullscreenAnimatorStyle enterForegroundStyle =
+      FullscreenAnimatorStyle::EXIT_FULLSCREEN;
+  if (animator_ && animator_.style == enterForegroundStyle)
     return;
-  CGFloat progress = model_->progress();
-  toolbar_reveal_animator_ =
-      [[ToolbarRevealAnimator alloc] initWithStartProgress:progress];
-  SetUpAnimator(&toolbar_reveal_animator_);
+  StopAnimating(true);
+
+  SetUpAnimator(enterForegroundStyle);
   for (auto& observer : observers_) {
-    observer.FullscreenWillEnterForeground(controller_,
-                                           toolbar_reveal_animator_);
+    observer.FullscreenWillEnterForeground(controller_, animator_);
   }
-  StartAnimator(&toolbar_reveal_animator_);
+  StartAnimator();
 }
 
 void FullscreenMediator::AnimateModelReset() {
-  if (toolbar_reveal_animator_)
+  FullscreenAnimatorStyle resetStyle = FullscreenAnimatorStyle::EXIT_FULLSCREEN;
+  if (animator_ && animator_.style == resetStyle)
     return;
-  CGFloat progress = model_->progress();
-  toolbar_reveal_animator_ =
-      [[ToolbarRevealAnimator alloc] initWithStartProgress:progress];
-  SetUpAnimator(&toolbar_reveal_animator_);
+  StopAnimating(true);
+
+  SetUpAnimator(resetStyle);
   for (auto& observer : observers_) {
-    observer.FullscreenModelWasReset(controller_, toolbar_reveal_animator_);
+    observer.FullscreenModelWasReset(controller_, animator_);
   }
-  StartAnimator(&toolbar_reveal_animator_);
+  StartAnimator();
 }
 
 void FullscreenMediator::Disconnect() {
-  [scroll_end_animator_ stopAnimation:YES];
-  scroll_end_animator_ = nil;
-  [scroll_to_top_animator_ stopAnimation:YES];
-  scroll_to_top_animator_ = nil;
-  [toolbar_reveal_animator_ stopAnimation:YES];
-  toolbar_reveal_animator_ = nil;
+  [animator_ stopAnimation:YES];
+  animator_ = nil;
   model_->RemoveObserver(this);
   model_ = nullptr;
   controller_ = nullptr;
@@ -110,17 +105,18 @@
 void FullscreenMediator::FullscreenModelScrollEventEnded(
     FullscreenModel* model) {
   DCHECK_EQ(model_, model);
-  DCHECK(!scroll_end_animator_);
-  CGFloat progress = model_->progress();
-  if (AreCGFloatsEqual(progress, 0.0) || AreCGFloatsEqual(progress, 1.0))
+  FullscreenAnimatorStyle scrollEndStyle =
+      model_->progress() >= 0.5 ? FullscreenAnimatorStyle::EXIT_FULLSCREEN
+                                : FullscreenAnimatorStyle::ENTER_FULLSCREEN;
+  if (animator_ && animator_.style == scrollEndStyle)
     return;
-  scroll_end_animator_ =
-      [[FullscreenScrollEndAnimator alloc] initWithStartProgress:progress];
-  SetUpAnimator(&scroll_end_animator_);
+  StopAnimating(true);
+
+  SetUpAnimator(scrollEndStyle);
   for (auto& observer : observers_) {
-    observer.FullscreenScrollEventEnded(controller_, scroll_end_animator_);
+    observer.FullscreenScrollEventEnded(controller_, animator_);
   }
-  StartAnimator(&scroll_end_animator_);
+  StartAnimator();
 }
 
 void FullscreenMediator::FullscreenModelWasReset(FullscreenModel* model) {
@@ -134,63 +130,41 @@
   }
 }
 
-void FullscreenMediator::SetUpAnimator(__strong FullscreenAnimator** animator) {
-  VerifyAnimatorPointer(animator);
-  [*animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
+void FullscreenMediator::SetUpAnimator(FullscreenAnimatorStyle style) {
+  DCHECK(!animator_);
+  animator_ =
+      [[FullscreenAnimator alloc] initWithStartProgress:model_->progress()
+                                                  style:style];
+  __weak FullscreenAnimator* weakAnimator = animator_;
+  FullscreenModel** modelPtr = &model_;
+  [animator_ addCompletion:^(UIViewAnimatingPosition finalPosition) {
     DCHECK_EQ(finalPosition, UIViewAnimatingPositionEnd);
-    if (!*animator)
+    if (!weakAnimator || !*modelPtr)
       return;
     model_->AnimationEndedWithProgress(
-        [*animator progressForAnimatingPosition:finalPosition]);
-    *animator = nil;
+        [weakAnimator progressForAnimatingPosition:finalPosition]);
+    animator_ = nil;
   }];
 }
 
-void FullscreenMediator::StartAnimator(__strong FullscreenAnimator** animator) {
-  // Start the animator if animations have been added to it, or reset the ivar
-  // otherwise.
-  VerifyAnimatorPointer(animator);
-  if ((*animator).hasAnimations) {
-    [*animator startAnimation];
+void FullscreenMediator::StartAnimator() {
+  // Only start the animator if animations have been added and it has a non-zero
+  // progress change.
+  if (animator_.hasAnimations &&
+      !AreCGFloatsEqual(animator_.startProgress, animator_.finalProgress)) {
+    [animator_ startAnimation];
   } else {
-    *animator = nil;
+    animator_ = nil;
   }
 }
 
 void FullscreenMediator::StopAnimating(bool update_model) {
-  if (!scroll_end_animator_ && !scroll_to_top_animator_ &&
-      !toolbar_reveal_animator_) {
+  if (!animator_)
     return;
-  }
 
-  // At most one animator should be non-nil.
-  DCHECK_EQ((scroll_end_animator_ ? 1 : 0) + (scroll_to_top_animator_ ? 1 : 0) +
-                (toolbar_reveal_animator_ ? 1 : 0),
-            1);
-
-  if (scroll_end_animator_)
-    StopAnimator(&scroll_end_animator_, update_model);
-  if (scroll_to_top_animator_)
-    StopAnimator(&scroll_to_top_animator_, update_model);
-  if (toolbar_reveal_animator_)
-    StopAnimator(&toolbar_reveal_animator_, update_model);
-}
-
-void FullscreenMediator::StopAnimator(__strong FullscreenAnimator** animator,
-                                      bool update_model) {
-  VerifyAnimatorPointer(animator);
-  DCHECK_EQ((*animator).state, UIViewAnimatingStateActive);
+  DCHECK_EQ(animator_.state, UIViewAnimatingStateActive);
   if (update_model)
-    model_->AnimationEndedWithProgress((*animator).currentProgress);
-  [*animator stopAnimation:YES];
-  *animator = nil;
-}
-
-void FullscreenMediator::VerifyAnimatorPointer(
-    __strong FullscreenAnimator** animator) const {
-  DCHECK(animator);
-  DCHECK(*animator);
-  DCHECK(*animator == scroll_end_animator_ ||
-         *animator == scroll_to_top_animator_ ||
-         *animator == toolbar_reveal_animator_);
+    model_->AnimationEndedWithProgress(animator_.currentProgress);
+  [animator_ stopAnimation:YES];
+  animator_ = nil;
 }
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_mediator_unittest.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_mediator_unittest.mm
index 46fb351..e393c406e 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_mediator_unittest.mm
@@ -5,7 +5,6 @@
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h"
 
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h"
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h"
 #import "ios/chrome/browser/ui/fullscreen/test/fullscreen_model_test_util.h"
 #import "ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller_observer.h"
 #import "ios/chrome/browser/ui/fullscreen/test/test_fullscreen_mediator.h"
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h b/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h
deleted file mode 100644
index e28afc0b..0000000
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_SCROLL_END_ANIMATOR_H_
-#define IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_SCROLL_END_ANIMATOR_H_
-
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_animator.h"
-
-// When a scroll event ends, the toolbar should be either completely hidden or
-// completely visible.  If a scroll ends and the toolbar is partly visible, this
-// animator will be provided to UI elements to animate its state to a hidden or
-// visible state.
-@interface FullscreenScrollEndAnimator : FullscreenAnimator
-
-- (instancetype)initWithStartProgress:(CGFloat)startProgress
-    NS_DESIGNATED_INITIALIZER;
-- (instancetype)initWithStartProgress:(CGFloat)startProgress
-                             duration:(NSTimeInterval)duration NS_UNAVAILABLE;
-
-@end
-
-#endif  // IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_SCROLL_END_ANIMATOR_H_
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.mm
deleted file mode 100644
index baf1116..0000000
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.mm
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h"
-
-#include <math.h>
-#include <algorithm>
-#include <memory>
-
-#include "base/logging.h"
-#import "ios/chrome/common/material_timing.h"
-#include "ui/gfx/geometry/cubic_bezier.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@implementation FullscreenScrollEndAnimator
-@synthesize finalProgress = _finalProgress;
-
-- (instancetype)initWithStartProgress:(CGFloat)startProgress {
-  // Scale the duration by the progress delta traversed in this animation.
-  // Since |finalProgress - startProgress| <= 0.5, the delta is multiplied by
-  // 2.0.
-  CGFloat finalProgress = roundf(startProgress);
-  NSTimeInterval duration =
-      2.0 * fabs(finalProgress - startProgress) * ios::material::kDuration1;
-  if (self = [super initWithStartProgress:startProgress duration:duration]) {
-    _finalProgress = finalProgress;
-  }
-  return self;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_to_top_animator.h b/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_to_top_animator.h
deleted file mode 100644
index 671b2868..0000000
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_to_top_animator.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_SCROLL_TO_TOP_ANIMATOR_H_
-#define IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_SCROLL_TO_TOP_ANIMATOR_H_
-
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_animator.h"
-
-// When the user taps on the status bar, scroll views are expected to scroll to
-// top.  This animator helps to coordinate that animation with a toolbar reveal
-// animation.
-@interface FullscreenScrollToTopAnimator : FullscreenAnimator
-
-- (instancetype)initWithStartProgress:(CGFloat)startProgress
-    NS_DESIGNATED_INITIALIZER;
-- (instancetype)initWithStartProgress:(CGFloat)startProgress
-                             duration:(NSTimeInterval)duration NS_UNAVAILABLE;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_SCROLL_TO_TOP_ANIMATOR_H_
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_to_top_animator.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_to_top_animator.mm
deleted file mode 100644
index ea14e7c..0000000
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_scroll_to_top_animator.mm
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_to_top_animator.h"
-
-#import "ios/chrome/common/material_timing.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@implementation FullscreenScrollToTopAnimator
-@synthesize finalProgress = _finalProgress;
-
-- (instancetype)initWithStartProgress:(CGFloat)startProgress {
-  if (self = [super initWithStartProgress:startProgress
-                                 duration:ios::material::kDuration1]) {
-    // Scrolling to top should always reveal the toolbar.
-    _finalProgress = 1.0;
-  }
-  return self;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater_unittest.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater_unittest.mm
index 0455995..95f010c 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater_unittest.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater_unittest.mm
@@ -5,8 +5,6 @@
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.h"
 
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_animator.h"
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h"
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_to_top_animator.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_element.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #include "testing/platform_test.h"
@@ -91,8 +89,9 @@
   ASSERT_FALSE(element().animator);
   // Create a test animator.  The start progress of 0.0 is a dummy value, as the
   // animator's progress properties are unused in this test.
-  FullscreenScrollEndAnimator* const kAnimator =
-      [[FullscreenScrollEndAnimator alloc] initWithStartProgress:0.0];
+  FullscreenAnimator* const kAnimator = [[FullscreenAnimator alloc]
+      initWithStartProgress:0.0
+                      style:FullscreenAnimatorStyle::ENTER_FULLSCREEN];
   observer()->FullscreenScrollEventEnded(nullptr, kAnimator);
   EXPECT_EQ(element().animator, kAnimator);
 }
diff --git a/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller_observer.mm b/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller_observer.mm
index ef0836f..50f13fb 100644
--- a/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller_observer.mm
+++ b/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller_observer.mm
@@ -4,7 +4,7 @@
 
 #import "ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller_observer.h"
 
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h"
+#import "ios/chrome/browser/ui/fullscreen/fullscreen_animator.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_mediator.mm b/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_mediator.mm
index 7e144a0..6fd7a6e 100644
--- a/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_mediator.mm
+++ b/ios/chrome/browser/ui/fullscreen/test/test_fullscreen_mediator.mm
@@ -5,7 +5,6 @@
 #import "ios/chrome/browser/ui/fullscreen/test/test_fullscreen_mediator.h"
 
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_observer.h"
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/fullscreen/toolbar_reveal_animator.h b/ios/chrome/browser/ui/fullscreen/toolbar_reveal_animator.h
deleted file mode 100644
index bcb9fe3e..0000000
--- a/ios/chrome/browser/ui/fullscreen/toolbar_reveal_animator.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_FULLSCREEN_TOOLBAR_REVEAL_ANIMATOR_H_
-#define IOS_CHROME_BROWSER_UI_FULLSCREEN_TOOLBAR_REVEAL_ANIMATOR_H_
-
-#import "ios/chrome/browser/ui/fullscreen/fullscreen_animator.h"
-
-// A FullscreenAnimator used to show the toolbar.
-@interface ToolbarRevealAnimator : FullscreenAnimator
-
-- (instancetype)initWithStartProgress:(CGFloat)startProgress
-    NS_DESIGNATED_INITIALIZER;
-- (instancetype)initWithStartProgress:(CGFloat)startProgress
-                             duration:(NSTimeInterval)duration NS_UNAVAILABLE;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_FULLSCREEN_TOOLBAR_REVEAL_ANIMATOR_H_
diff --git a/ios/chrome/browser/ui/fullscreen/toolbar_reveal_animator.mm b/ios/chrome/browser/ui/fullscreen/toolbar_reveal_animator.mm
deleted file mode 100644
index e6e9af6..0000000
--- a/ios/chrome/browser/ui/fullscreen/toolbar_reveal_animator.mm
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/fullscreen/toolbar_reveal_animator.h"
-
-#import "ios/chrome/common/material_timing.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@implementation ToolbarRevealAnimator
-@synthesize finalProgress = _finalProgress;
-
-- (instancetype)initWithStartProgress:(CGFloat)startProgress {
-  if (self = [super initWithStartProgress:startProgress
-                                 duration:ios::material::kDuration1]) {
-    // The toolbar should be shown when the fullscreen state is reset.
-    _finalProgress = 1.0;
-  }
-  return self;
-}
-
-@end
diff --git a/ios/web/web_state/favicon_callbacks_inttest.mm b/ios/web/web_state/favicon_callbacks_inttest.mm
index dd02d72f..a487044 100644
--- a/ios/web/web_state/favicon_callbacks_inttest.mm
+++ b/ios/web/web_state/favicon_callbacks_inttest.mm
@@ -4,6 +4,7 @@
 
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#import "ios/testing/wait_util.h"
 #include "ios/web/public/favicon_url.h"
 #import "ios/web/public/test/web_test_with_web_state.h"
 #import "ios/web/public/web_state/web_state.h"
@@ -13,6 +14,8 @@
 #error "This file requires ARC support."
 #endif
 
+using testing::WaitUntilConditionOrTimeout;
+
 namespace web {
 
 namespace {
@@ -73,9 +76,9 @@
   ASSERT_TRUE(observer()->favicon_url_candidates().empty());
   LoadHtml(@"<link rel='shortcut icon' href='http://fav.ico'>");
 
-  WaitForCondition(^{
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForActionTimeout, ^{
     return observer()->favicon_url_updated();
-  });
+  }));
 
   const std::vector<FaviconURL>& favicons =
       observer()->favicon_url_candidates();
@@ -90,9 +93,9 @@
   ASSERT_TRUE(observer()->favicon_url_candidates().empty());
   LoadHtml(@"<link rel='icon' href='http://fav.ico'>");
 
-  WaitForCondition(^{
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForActionTimeout, ^{
     return observer()->favicon_url_updated();
-  });
+  }));
 
   const std::vector<FaviconURL>& favicons =
       observer()->favicon_url_candidates();
@@ -108,9 +111,9 @@
   LoadHtml(@"<link rel='apple-touch-icon' href='http://fav.ico'>",
            GURL("https://chromium.test"));
 
-  WaitForCondition(^{
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForActionTimeout, ^{
     return observer()->favicon_url_updated();
-  });
+  }));
 
   const std::vector<FaviconURL>& favicons =
       observer()->favicon_url_candidates();
@@ -129,9 +132,9 @@
   LoadHtml(@"<link rel='apple-touch-icon-precomposed' href='http://fav.ico'>",
            GURL("https://chromium.test"));
 
-  WaitForCondition(^{
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForActionTimeout, ^{
     return observer()->favicon_url_updated();
-  });
+  }));
 
   const std::vector<FaviconURL>& favicons =
       observer()->favicon_url_candidates();
@@ -149,9 +152,9 @@
   ASSERT_TRUE(observer()->favicon_url_candidates().empty());
   LoadHtml(@"<html></html>", GURL("https://chromium.test/test/test.html"));
 
-  WaitForCondition(^{
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForActionTimeout, ^{
     return observer()->favicon_url_updated();
-  });
+  }));
 
   const std::vector<FaviconURL>& favicons =
       observer()->favicon_url_candidates();
@@ -167,9 +170,9 @@
   LoadHtml(@"<html></html>",
            GURL("https://chromium.test/test/test.html?q1#h1"));
 
-  WaitForCondition(^{
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForActionTimeout, ^{
     return observer()->favicon_url_updated();
-  });
+  }));
 
   const std::vector<FaviconURL>& favicons =
       observer()->favicon_url_candidates();
@@ -187,9 +190,9 @@
             "<link rel='apple-touch-icon' href='http://fav2.ico'>"
             "<link rel='apple-touch-icon-precomposed' href='http://fav3.ico'>");
 
-  WaitForCondition(^{
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForActionTimeout, ^{
     return observer()->favicon_url_updated();
-  });
+  }));
 
   const std::vector<FaviconURL>& favicons =
       observer()->favicon_url_candidates();
@@ -214,9 +217,9 @@
   LoadHtml(@"<html><head><link rel='icon' href='http://'></head></html>",
            GURL("https://chromium.test"));
 
-  WaitForCondition(^{
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForActionTimeout, ^{
     return observer()->favicon_url_updated();
-  });
+  }));
 
   const std::vector<FaviconURL>& favicons =
       observer()->favicon_url_candidates();
@@ -231,9 +234,9 @@
   ASSERT_TRUE(observer()->favicon_url_candidates().empty());
   LoadHtml(@"<head><link rel='icon' href=''></head>");
 
-  WaitForCondition(^{
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForActionTimeout, ^{
     return observer()->favicon_url_updated();
-  });
+  }));
 
   const std::vector<FaviconURL>& favicons =
       observer()->favicon_url_candidates();
@@ -251,9 +254,9 @@
       @"<link rel='icon' href='http://fav.ico' sizes='10x20 30x40'><link "
       @"rel='apple-touch-icon' href='http://fav2.ico' sizes='10x20 asdfx'>");
 
-  WaitForCondition(^{
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForActionTimeout, ^{
     return observer()->favicon_url_updated();
-  });
+  }));
 
   const std::vector<FaviconURL>& favicons =
       observer()->favicon_url_candidates();
diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc
index 3751965..6c305112 100644
--- a/media/base/android/media_drm_bridge.cc
+++ b/media/base/android/media_drm_bridge.cc
@@ -19,6 +19,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -948,6 +949,9 @@
 
   j_media_crypto_ = std::move(j_media_crypto);
 
+  UMA_HISTOGRAM_BOOLEAN("Media.EME.MediaCryptoAvailable",
+                        !j_media_crypto_->is_null());
+
   if (media_crypto_ready_cb_.is_null())
     return;
 
diff --git a/media/gpu/video_decode_accelerator_unittest.cc b/media/gpu/video_decode_accelerator_unittest.cc
index 85254a5..871c0378 100644
--- a/media/gpu/video_decode_accelerator_unittest.cc
+++ b/media/gpu/video_decode_accelerator_unittest.cc
@@ -498,6 +498,7 @@
   LOG_ASSERT((pixel_format_ == PIXEL_FORMAT_UNKNOWN) ||
              (pixel_format_ == pixel_format));
   pixel_format_ = pixel_format;
+  frame_size_ = dimensions;
 
   texture_target_ = texture_target;
   for (uint32_t i = 0; i < requested_num_of_buffers; ++i) {
@@ -561,7 +562,7 @@
 
   gfx::Rect visible_rect = picture.visible_rect();
   if (!visible_rect.IsEmpty())
-    EXPECT_EQ(gfx::Rect(frame_size_), visible_rect);
+    EXPECT_TRUE(gfx::Rect(frame_size_).Contains(visible_rect));
 
   base::TimeTicks now = base::TimeTicks::Now();
 
diff --git a/media/test/data/README b/media/test/data/README
index 0cb2312e9..c48eb69 100644
--- a/media/test/data/README
+++ b/media/test/data/README
@@ -283,6 +283,21 @@
   not specified to the last bit and GLES shader/texture filtering
   precision varies.
 
+// VDA test files: resolution_change_500frames
+resolution_change_500frames-vp8.ivf
+resolution_change_500frames-vp9.ivf
+  Dumped compressed stream of videos on http://crosvideo.appspot.com manually
+  changing resolutions at random.
+  Those contain 144p, 240p, 360p, 480p, 720p, and 1080p frames.
+  Those frame sizes can be found by
+  ffprobe -show_frames resolution_change_500frames.vp8
+
+// VDA test files: switch_1080p_720p_240frames
+switch_1080p_720p_240frames.h264
+  Extract 240 frames using ffmpeg from
+  http://commondatastorage.googleapis.com/chromiumos-test-assets-public/MSE/switch_1080p_720p.mp4.
+  The frame sizes change between 1080p and 720p every 24 frames.
+
 // VEA test files:
 bear_320x192_40frames.yuv
   First 40 raw i420 frames of bear-1280x720.mp4 scaled down to 320x192 for
diff --git a/media/test/data/resolution_change_500frames-vp8.ivf b/media/test/data/resolution_change_500frames-vp8.ivf
new file mode 100644
index 0000000..0a82659
--- /dev/null
+++ b/media/test/data/resolution_change_500frames-vp8.ivf
Binary files differ
diff --git a/media/test/data/resolution_change_500frames-vp9.ivf b/media/test/data/resolution_change_500frames-vp9.ivf
new file mode 100644
index 0000000..1ea03439
--- /dev/null
+++ b/media/test/data/resolution_change_500frames-vp9.ivf
Binary files differ
diff --git a/media/test/data/switch_1080p_720p_240frames.h264 b/media/test/data/switch_1080p_720p_240frames.h264
new file mode 100644
index 0000000..10d9616
--- /dev/null
+++ b/media/test/data/switch_1080p_720p_240frames.h264
Binary files differ
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h
index c9626316..bf00e35e 100644
--- a/net/base/net_error_list.h
+++ b/net/base/net_error_list.h
@@ -748,6 +748,12 @@
 // credentials or presents a fresh invalid certificate.
 NET_ERROR(TOO_MANY_RETRIES, -375)
 
+// Received an HTTP/2 frame on a closed stream.
+NET_ERROR(SPDY_STREAM_CLOSED, -376)
+
+// Client is refusing an HTTP/2 stream.
+NET_ERROR(SPDY_CLIENT_REFUSED_STREAM, -377)
+
 // The cache does not have the requested entry.
 NET_ERROR(CACHE_MISS, -400)
 
diff --git a/net/reporting/reporting_cache.cc b/net/reporting/reporting_cache.cc
index 3a85b4b..0df7956 100644
--- a/net/reporting/reporting_cache.cc
+++ b/net/reporting/reporting_cache.cc
@@ -335,11 +335,14 @@
         std::vector<base::Value> endpoint_list;
         for (const ReportingClient* client : clients) {
           base::Value endpoint_dict(base::Value::Type::DICTIONARY);
-          // Reporting defines the group as a whole to have an expiration time,
-          // not the individual endpoints within the group.
+          // Reporting defines the group as a whole to have an expiration time
+          // and subdomains flag, not the individual endpoints within the group.
           group_dict.SetKey(
               "expires",
               base::Value(NetLog::TickCountToString(client->expires)));
+          group_dict.SetKey("includeSubdomains",
+                            base::Value(client->subdomains ==
+                                        ReportingClient::Subdomains::INCLUDE));
           endpoint_dict.SetKey("url", base::Value(client->endpoint.spec()));
           endpoint_dict.SetKey("priority", base::Value(client->priority));
           endpoint_dict.SetKey("weight", base::Value(client->weight));
diff --git a/net/reporting/reporting_cache_unittest.cc b/net/reporting/reporting_cache_unittest.cc
index fbd6e92..a2fbb9e 100644
--- a/net/reporting/reporting_cache_unittest.cc
+++ b/net/reporting/reporting_cache_unittest.cc
@@ -409,7 +409,7 @@
   const base::TimeTicks expires =
       base::TimeTicks() + base::TimeDelta::FromDays(7);
   SetClient(kOrigin1_, kEndpoint1_, false, kGroup1_, expires);
-  SetClient(kOrigin2_, kEndpoint2_, false, kGroup1_, expires);
+  SetClient(kOrigin2_, kEndpoint2_, true, kGroup1_, expires);
 
   // Add some reports so that we can test the upload counts.
   const ReportingReport* report1a = AddAndReturnReport(
@@ -433,6 +433,7 @@
             {
               "name": "group1",
               "expires": "604800000",
+              "includeSubdomains": false,
               "endpoints": [
                 {"url": "https://endpoint1/", "priority": 0, "weight": 1,
                  "successful": {"uploads": 1, "reports": 2},
@@ -447,6 +448,7 @@
             {
               "name": "group1",
               "expires": "604800000",
+              "includeSubdomains": true,
               "endpoints": [
                 {"url": "https://endpoint2/", "priority": 0, "weight": 1,
                  "successful": {"uploads": 0, "reports": 0},
diff --git a/net/spdy/chromium/spdy_http_stream.cc b/net/spdy/chromium/spdy_http_stream.cc
index 19a5df9..835e13b 100644
--- a/net/spdy/chromium/spdy_http_stream.cc
+++ b/net/spdy/chromium/spdy_http_stream.cc
@@ -292,7 +292,7 @@
   request_callback_.Reset();
   response_callback_.Reset();
   if (stream_) {
-    stream_->Cancel();
+    stream_->Cancel(ERR_ABORTED);
     DCHECK(!stream_);
   }
 }
@@ -458,23 +458,16 @@
   was_alpn_negotiated_ = stream_->WasAlpnNegotiated();
 }
 
-void SpdyHttpStream::ResetStreamInternal() {
-  spdy_session_->ResetStream(stream()->stream_id(), ERROR_CODE_INTERNAL_ERROR,
-                             SpdyString());
+void SpdyHttpStream::ResetStream(int error) {
+  spdy_session_->ResetStream(stream()->stream_id(), error, SpdyString());
 }
 
 void SpdyHttpStream::OnRequestBodyReadCompleted(int status) {
   if (status < 0) {
     DCHECK_NE(ERR_IO_PENDING, status);
-    // Post |request_callback_| with received error.  This should be posted
-    // before ResetStreamInternal, because the latter would call
-    // |request_callback_| via OnClose with an error code potentially different
-    // from |status|.
-    MaybePostRequestCallback(status);
-
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(&SpdyHttpStream::ResetStreamInternal,
-                                  weak_factory_.GetWeakPtr()));
+        FROM_HERE, base::BindOnce(&SpdyHttpStream::ResetStream,
+                                  weak_factory_.GetWeakPtr(), status));
 
     return;
   }
diff --git a/net/spdy/chromium/spdy_http_stream.h b/net/spdy/chromium/spdy_http_stream.h
index eab0f110..34c80084 100644
--- a/net/spdy/chromium/spdy_http_stream.h
+++ b/net/spdy/chromium/spdy_http_stream.h
@@ -98,7 +98,7 @@
   void InitializeStreamHelper();
 
   // Helper function used for resetting stream from inside the stream.
-  void ResetStreamInternal();
+  void ResetStream(int error);
 
   // Must be called only when |request_info_| is non-NULL.
   bool HasUploadData() const;
diff --git a/net/spdy/chromium/spdy_network_transaction_unittest.cc b/net/spdy/chromium/spdy_network_transaction_unittest.cc
index 3e099582..37c1742 100644
--- a/net/spdy/chromium/spdy_network_transaction_unittest.cc
+++ b/net/spdy/chromium/spdy_network_transaction_unittest.cc
@@ -6149,7 +6149,7 @@
 
   base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(callback.have_result());
-  EXPECT_THAT(callback.WaitForResult(), IsError(ERR_SPDY_PROTOCOL_ERROR));
+  EXPECT_THAT(callback.WaitForResult(), IsError(ERR_SPDY_FLOW_CONTROL_ERROR));
   helper.VerifyDataConsumed();
 }
 
diff --git a/net/spdy/chromium/spdy_proxy_client_socket.cc b/net/spdy/chromium/spdy_proxy_client_socket.cc
index c79b819..6a6dcce 100644
--- a/net/spdy/chromium/spdy_proxy_client_socket.cc
+++ b/net/spdy/chromium/spdy_proxy_client_socket.cc
@@ -138,7 +138,7 @@
   if (spdy_stream_.get()) {
     // This will cause OnClose to be invoked, which takes care of
     // cleaning up all the internal state.
-    spdy_stream_->Cancel();
+    spdy_stream_->Cancel(ERR_ABORTED);
     DCHECK(!spdy_stream_.get());
   }
 }
diff --git a/net/spdy/chromium/spdy_session.cc b/net/spdy/chromium/spdy_session.cc
index 78e0c289..267da7c 100644
--- a/net/spdy/chromium/spdy_session.cc
+++ b/net/spdy/chromium/spdy_session.cc
@@ -896,7 +896,7 @@
     return;
 
   DCHECK(active_streams_.find(stream_id) != active_streams_.end());
-  ResetStream(stream_id, ERROR_CODE_CANCEL, "Cancelled push stream.");
+  ResetStream(stream_id, ERR_ABORTED, "Cancelled push stream.");
 }
 
 void SpdySession::InitializeWithSocket(
@@ -1161,7 +1161,7 @@
 }
 
 void SpdySession::ResetStream(SpdyStreamId stream_id,
-                              SpdyErrorCode error_code,
+                              int error,
                               const SpdyString& description) {
   DCHECK_NE(stream_id, 0u);
 
@@ -1171,7 +1171,7 @@
     return;
   }
 
-  ResetStreamIterator(it, error_code, description);
+  ResetStreamIterator(it, error, description);
 }
 
 bool SpdySession::IsStreamActive(SpdyStreamId stream_id) const {
@@ -1906,17 +1906,30 @@
 }
 
 void SpdySession::ResetStreamIterator(ActiveStreamMap::iterator it,
-                                      SpdyErrorCode error_code,
+                                      int error,
                                       const SpdyString& description) {
   // Send the RST_STREAM frame first as CloseActiveStreamIterator()
   // may close us.
+  SpdyErrorCode error_code = ERROR_CODE_PROTOCOL_ERROR;
+  if (error == ERR_FAILED) {
+    error_code = ERROR_CODE_INTERNAL_ERROR;
+  } else if (error == ERR_ABORTED) {
+    error_code = ERROR_CODE_CANCEL;
+  } else if (error == ERR_SPDY_FLOW_CONTROL_ERROR) {
+    error_code = ERROR_CODE_FLOW_CONTROL_ERROR;
+  } else if (error == ERR_TIMED_OUT ||
+             error == ERR_SPDY_CLIENT_REFUSED_STREAM) {
+    error_code = ERROR_CODE_REFUSED_STREAM;
+  } else if (error == ERR_SPDY_STREAM_CLOSED) {
+    error_code = ERROR_CODE_STREAM_CLOSED;
+  }
   SpdyStreamId stream_id = it->first;
   RequestPriority priority = it->second->priority();
   EnqueueResetStreamFrame(stream_id, priority, error_code, description);
 
   // Removes any pending writes for the stream except for possibly an
   // in-flight one.
-  CloseActiveStreamIterator(it, ERR_SPDY_PROTOCOL_ERROR);
+  CloseActiveStreamIterator(it, error);
 }
 
 void SpdySession::EnqueueResetStreamFrame(SpdyStreamId stream_id,
@@ -2730,8 +2743,7 @@
   LogAbandonedActiveStream(active_it, ERR_TIMED_OUT);
   // CloseActiveStreamIterator() will remove the stream from
   // |pool_->push_promise_index()|.
-  ResetStreamIterator(active_it, ERROR_CODE_REFUSED_STREAM,
-                      "Stream not claimed.");
+  ResetStreamIterator(active_it, ERR_TIMED_OUT, "Stream not claimed.");
 }
 
 void SpdySession::OnError(
@@ -2759,7 +2771,7 @@
     return;
   }
 
-  ResetStreamIterator(it, ERROR_CODE_PROTOCOL_ERROR, description);
+  ResetStreamIterator(it, ERR_SPDY_PROTOCOL_ERROR, description);
 }
 
 void SpdySession::OnPing(SpdyPingId unique_id, bool is_ack) {
@@ -3027,7 +3039,7 @@
 
     if (delta_window_size < 1) {
       ResetStreamIterator(
-          it, ERROR_CODE_FLOW_CONTROL_ERROR,
+          it, ERR_SPDY_FLOW_CONTROL_ERROR,
           "Received WINDOW_UPDATE with an invalid delta_window_size.");
       return;
     }
@@ -3087,7 +3099,7 @@
     if (max_concurrent_pushed_streams_ &&
         num_active_pushed_streams_ >= max_concurrent_pushed_streams_) {
       // TODO(https://crbug.com/831536): Add histogram.
-      ResetStream(stream_id, ERROR_CODE_REFUSED_STREAM,
+      ResetStream(stream_id, ERR_SPDY_CLIENT_REFUSED_STREAM,
                   "Stream concurrency limit reached.");
       return;
     }
diff --git a/net/spdy/chromium/spdy_session.h b/net/spdy/chromium/spdy_session.h
index be58f957..0a31f4d 100644
--- a/net/spdy/chromium/spdy_session.h
+++ b/net/spdy/chromium/spdy_session.h
@@ -380,7 +380,7 @@
   // stream with the given ID, which must exist and be active. Note
   // that that stream may hold the last reference to the session.
   void ResetStream(SpdyStreamId stream_id,
-                   SpdyErrorCode error_code,
+                   int error,
                    const SpdyString& description);
 
   // Check if a stream is active.
@@ -611,7 +611,7 @@
   // Calls EnqueueResetStreamFrame() and then
   // CloseActiveStreamIterator().
   void ResetStreamIterator(ActiveStreamMap::iterator it,
-                           SpdyErrorCode error_code,
+                           int status,
                            const SpdyString& description);
 
   // Send a RST_STREAM frame with the given parameters. There should
diff --git a/net/spdy/chromium/spdy_session_pool_unittest.cc b/net/spdy/chromium/spdy_session_pool_unittest.cc
index efbb9205..178f694 100644
--- a/net/spdy/chromium/spdy_session_pool_unittest.cc
+++ b/net/spdy/chromium/spdy_session_pool_unittest.cc
@@ -498,7 +498,7 @@
       EXPECT_TRUE(session2->is_active());
       EXPECT_TRUE(session2->IsAvailable());
 
-      spdy_stream2->Cancel();
+      spdy_stream2->Cancel(ERR_ABORTED);
       EXPECT_FALSE(spdy_stream);
       EXPECT_FALSE(spdy_stream1);
       EXPECT_FALSE(spdy_stream2);
diff --git a/net/spdy/chromium/spdy_session_unittest.cc b/net/spdy/chromium/spdy_session_unittest.cc
index 0b6aaf1..96b77c3 100644
--- a/net/spdy/chromium/spdy_session_unittest.cc
+++ b/net/spdy/chromium/spdy_session_unittest.cc
@@ -1395,7 +1395,7 @@
 
   // Cancel the first stream. A callback to unstall the second stream was
   // posted. Don't run it yet.
-  stream1->Cancel();
+  stream1->Cancel(ERR_ABORTED);
 
   EXPECT_EQ(0u, num_created_streams());
   EXPECT_EQ(0u, pending_create_stream_queue_size(MEDIUM));
@@ -1415,7 +1415,7 @@
 
   // Cancel the third stream and run the message loop. Verify that the second
   // stream creation now completes.
-  stream3->Cancel();
+  stream3->Cancel(ERR_ABORTED);
   base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1u, num_created_streams());
@@ -2028,7 +2028,7 @@
       IsError(ERR_IO_PENDING));
 
   // Release the first one, this will allow the second to be created.
-  spdy_stream1->Cancel();
+  spdy_stream1->Cancel(ERR_ABORTED);
   EXPECT_FALSE(spdy_stream1);
 
   request.CancelRequest();
@@ -2335,7 +2335,7 @@
 
   EXPECT_EQ(0u, spdy_stream1->stream_id());
 
-  spdy_stream1->Cancel();
+  spdy_stream1->Cancel(ERR_ABORTED);
   EXPECT_FALSE(spdy_stream1);
 
   EXPECT_EQ(0u, delegate1.stream_id());
@@ -2345,7 +2345,7 @@
   EXPECT_EQ(0u, delegate1.stream_id());
   EXPECT_EQ(1u, delegate2.stream_id());
 
-  spdy_stream2->Cancel();
+  spdy_stream2->Cancel(ERR_ABORTED);
   EXPECT_FALSE(spdy_stream2);
 }
 
@@ -2679,7 +2679,7 @@
 
   // Ensure we don't crash while closing the stream (which closes the
   // session).
-  spdy_stream->Cancel();
+  spdy_stream->Cancel(ERR_ABORTED);
 
   EXPECT_FALSE(spdy_stream);
   EXPECT_TRUE(delegate.StreamIsClosed());
@@ -2923,7 +2923,7 @@
 
   // Cancel the first stream; this will allow the second stream to be created.
   EXPECT_TRUE(spdy_stream1);
-  spdy_stream1->Cancel();
+  spdy_stream1->Cancel(ERR_ABORTED);
   EXPECT_FALSE(spdy_stream1);
 
   EXPECT_THAT(callback2.WaitForResult(), IsOk());
@@ -2933,7 +2933,7 @@
 
   // Cancel the second stream; this will allow the third stream to be created.
   base::WeakPtr<SpdyStream> spdy_stream2 = request2.ReleaseStream();
-  spdy_stream2->Cancel();
+  spdy_stream2->Cancel(ERR_ABORTED);
   EXPECT_FALSE(spdy_stream2);
 
   EXPECT_THAT(callback3.WaitForResult(), IsOk());
@@ -2943,7 +2943,7 @@
 
   // Cancel the third stream.
   base::WeakPtr<SpdyStream> spdy_stream3 = request3.ReleaseStream();
-  spdy_stream3->Cancel();
+  spdy_stream3->Cancel(ERR_ABORTED);
   EXPECT_FALSE(spdy_stream3);
   EXPECT_EQ(0u, num_active_streams());
   EXPECT_EQ(kInitialMaxConcurrentStreams - 1, num_created_streams());
@@ -3633,7 +3633,7 @@
   // Cancelling the request should result in the session's socket being
   // closed, since the pool is stalled.
   ASSERT_TRUE(spdy_stream1.get());
-  spdy_stream1->Cancel();
+  spdy_stream1->Cancel(ERR_ABORTED);
   base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(pool->IsStalled());
   EXPECT_THAT(callback2.WaitForResult(), IsOk());
@@ -3798,7 +3798,7 @@
   EXPECT_EQ(spdy_stream1->send_window_size(), window_size);
 
   // Release the first one, this will allow the second to be created.
-  spdy_stream1->Cancel();
+  spdy_stream1->Cancel(ERR_ABORTED);
   EXPECT_FALSE(spdy_stream1);
 
   base::WeakPtr<SpdyStream> spdy_stream2 =
@@ -3806,7 +3806,7 @@
                                 MEDIUM, NetLogWithSource());
   ASSERT_TRUE(spdy_stream2);
   EXPECT_EQ(spdy_stream2->send_window_size(), window_size);
-  spdy_stream2->Cancel();
+  spdy_stream2->Cancel(ERR_ABORTED);
   EXPECT_FALSE(spdy_stream2);
 
   EXPECT_TRUE(session_);
diff --git a/net/spdy/chromium/spdy_stream.cc b/net/spdy/chromium/spdy_stream.cc
index b3b300a3..ee7eb81b 100644
--- a/net/spdy/chromium/spdy_stream.cc
+++ b/net/spdy/chromium/spdy_stream.cc
@@ -204,7 +204,7 @@
 void SpdyStream::DetachDelegate() {
   DCHECK(!IsClosed());
   delegate_ = NULL;
-  Cancel();
+  Cancel(ERR_ABORTED);
 }
 
 void SpdyStream::SetPriority(RequestPriority priority) {
@@ -271,7 +271,7 @@
         "Received WINDOW_UPDATE [delta: %d] for stream %d overflows "
         "send_window_size_ [current: %d]",
         delta_window_size, stream_id_, send_window_size_);
-    session_->ResetStream(stream_id_, ERROR_CODE_FLOW_CONTROL_ERROR, desc);
+    session_->ResetStream(stream_id_, ERR_SPDY_FLOW_CONTROL_ERROR, desc);
   }
 }
 
@@ -341,7 +341,7 @@
   // the peer, that means that the receive window is not being respected.
   if (delta_window_size > recv_window_size_ - unacked_recv_window_bytes_) {
     session_->ResetStream(
-        stream_id_, ERROR_CODE_FLOW_CONTROL_ERROR,
+        stream_id_, ERR_SPDY_FLOW_CONTROL_ERROR,
         "delta_window_size is " + base::IntToString(delta_window_size) +
             " in DecreaseRecvWindowSize, which is larger than the receive " +
             "window size of " + base::IntToString(recv_window_size_));
@@ -389,7 +389,7 @@
         if (it == response_headers.end()) {
           const SpdyString error("Response headers do not include :status.");
           LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
-          session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
+          session_->ResetStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR, error);
           return;
         }
 
@@ -397,7 +397,7 @@
         if (!StringToInt(it->second, &status)) {
           const SpdyString error("Cannot parse :status.");
           LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
-          session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
+          session_->ResetStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR, error);
           return;
         }
 
@@ -422,7 +422,7 @@
           if (io_state_ == STATE_IDLE) {
             const SpdyString error("Response received before request sent.");
             LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
-            session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
+            session_->ResetStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR, error);
             return;
           }
           break;
@@ -453,7 +453,7 @@
       if (type_ == SPDY_PUSH_STREAM) {
         const SpdyString error("Trailers not supported for push stream.");
         LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
-        session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
+        session_->ResetStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR, error);
         return;
       }
 
@@ -465,12 +465,12 @@
       // No further header blocks are allowed after trailers.
       const SpdyString error("Header block received after trailers.");
       LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
-      session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
+      session_->ResetStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR, error);
       break;
   }
 }
 
-bool SpdyStream::ShouldRetryRSTPushStream() {
+bool SpdyStream::ShouldRetryRSTPushStream() const {
   // Retry if the stream is a pushed stream, has been claimed, but did not yet
   // receive response headers
   return (response_headers_.empty() && type_ == SPDY_PUSH_STREAM && delegate_);
@@ -494,21 +494,21 @@
   if (response_state_ == READY_FOR_HEADERS) {
     const SpdyString error("DATA received before headers.");
     LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
-    session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
+    session_->ResetStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR, error);
     return;
   }
 
   if (response_state_ == TRAILERS_RECEIVED && buffer) {
     const SpdyString error("DATA received after trailers.");
     LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
-    session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR, error);
+    session_->ResetStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR, error);
     return;
   }
 
   if (io_state_ == STATE_HALF_CLOSED_REMOTE) {
     const SpdyString error("DATA received on half-closed (remove) stream.");
-    LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
-    session_->ResetStream(stream_id_, ERROR_CODE_STREAM_CLOSED, error);
+    LogStreamError(ERR_SPDY_STREAM_CLOSED, error);
+    session_->ResetStream(stream_id_, ERR_SPDY_STREAM_CLOSED, error);
     return;
   }
 
@@ -679,15 +679,15 @@
   stream_id_ = 0;
 }
 
-void SpdyStream::Cancel() {
+void SpdyStream::Cancel(int error) {
   // We may be called again from a delegate's OnClose().
   if (io_state_ == STATE_CLOSED)
     return;
 
   if (stream_id_ != 0) {
-    session_->ResetStream(stream_id_, ERROR_CODE_CANCEL, SpdyString());
+    session_->ResetStream(stream_id_, error, SpdyString());
   } else {
-    session_->CloseCreatedStream(GetWeakPtr(), ERROR_CODE_CANCEL);
+    session_->CloseCreatedStream(GetWeakPtr(), error);
   }
   // |this| is invalid at this point.
 }
@@ -899,7 +899,7 @@
 void SpdyStream::SaveResponseHeaders(const SpdyHeaderBlock& response_headers) {
   DCHECK(response_headers_.empty());
   if (response_headers.find("transfer-encoding") != response_headers.end()) {
-    session_->ResetStream(stream_id_, ERROR_CODE_PROTOCOL_ERROR,
+    session_->ResetStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR,
                           "Received transfer-encoding header");
     return;
   }
diff --git a/net/spdy/chromium/spdy_stream.h b/net/spdy/chromium/spdy_stream.h
index b3fabf4..d6d8f0ef 100644
--- a/net/spdy/chromium/spdy_stream.h
+++ b/net/spdy/chromium/spdy_stream.h
@@ -303,7 +303,7 @@
 
   // If this stream is active, reset it, and close it otherwise. In
   // either case the stream is deleted.
-  void Cancel();
+  void Cancel(int error);
 
   // Close this stream without sending a RST_STREAM and delete
   // it.
@@ -387,12 +387,12 @@
   int64_t raw_received_bytes() const { return raw_received_bytes_; }
   int64_t raw_sent_bytes() const { return raw_sent_bytes_; }
   int recv_bytes() const { return recv_bytes_; }
-  bool ShouldRetryRSTPushStream();
+  bool ShouldRetryRSTPushStream() const;
 
   bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const;
 
-  const SpdyHeaderBlock& request_headers() { return request_headers_; }
-  const SpdyHeaderBlock& response_headers() { return response_headers_; }
+  const SpdyHeaderBlock& request_headers() const { return request_headers_; }
+  const SpdyHeaderBlock& response_headers() const { return response_headers_; }
 
   // Returns the estimate of dynamically allocated memory in bytes.
   size_t EstimateMemoryUsage() const;
diff --git a/net/spdy/chromium/spdy_stream_test_util.cc b/net/spdy/chromium/spdy_stream_test_util.cc
index 24919ce..dba10ad9 100644
--- a/net/spdy/chromium/spdy_stream_test_util.cc
+++ b/net/spdy/chromium/spdy_stream_test_util.cc
@@ -151,7 +151,7 @@
 
 void StreamDelegateCloseOnHeaders::OnHeadersReceived(
     const SpdyHeaderBlock& response_headers) {
-  stream()->Cancel();
+  stream()->Cancel(ERR_ABORTED);
 }
 
 }  // namespace test
diff --git a/net/spdy/chromium/spdy_stream_unittest.cc b/net/spdy/chromium/spdy_stream_unittest.cc
index b803d20..8144b7f 100644
--- a/net/spdy/chromium/spdy_stream_unittest.cc
+++ b/net/spdy/chromium/spdy_stream_unittest.cc
@@ -1249,7 +1249,7 @@
   data.Resume();
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR));
+  EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_FLOW_CONTROL_ERROR));
 }
 
 // Functions used with
@@ -1543,7 +1543,7 @@
   EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND),
               IsError(ERR_IO_PENDING));
 
-  EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR));
+  EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_STREAM_CLOSED));
 
   base::RunLoop().RunUntilIdle();
 
diff --git a/net/spdy/chromium/spdy_test_util_common.cc b/net/spdy/chromium/spdy_test_util_common.cc
index 7f2c121..14bfc12 100644
--- a/net/spdy/chromium/spdy_test_util_common.cc
+++ b/net/spdy/chromium/spdy_test_util_common.cc
@@ -255,7 +255,7 @@
 void StreamReleaserCallback::OnComplete(
     SpdyStreamRequest* request, int result) {
   if (result == OK)
-    request->ReleaseStream()->Cancel();
+    request->ReleaseStream()->Cancel(ERR_ABORTED);
   SetResult(result);
 }
 
diff --git a/services/audio/BUILD.gn b/services/audio/BUILD.gn
index 7c45e38..be500ae 100644
--- a/services/audio/BUILD.gn
+++ b/services/audio/BUILD.gn
@@ -43,6 +43,8 @@
     "input_stream.h",
     "local_muter.cc",
     "local_muter.h",
+    "loopback_stream.cc",
+    "loopback_stream.h",
     "output_controller.cc",
     "output_controller.h",
     "output_stream.cc",
@@ -82,6 +84,7 @@
     "group_coordinator_unittest.cc",
     "input_stream_unittest.cc",
     "local_muter_unittest.cc",
+    "loopback_stream_unittest.cc",
     "output_controller_unittest.cc",
     "output_stream_unittest.cc",
     "snooper_node_unittest.cc",
diff --git a/services/audio/loopback_stream.cc b/services/audio/loopback_stream.cc
new file mode 100644
index 0000000..49427c4
--- /dev/null
+++ b/services/audio/loopback_stream.cc
@@ -0,0 +1,356 @@
+// Copyright 2018 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 "services/audio/loopback_stream.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/bind.h"
+#include "base/stl_util.h"
+#include "base/sync_socket.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/default_tick_clock.h"
+#include "media/base/audio_bus.h"
+#include "media/base/vector_math.h"
+#include "mojo/public/cpp/system/buffer.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+
+namespace audio {
+
+// static
+constexpr double LoopbackStream::kMaxVolume;
+
+// static
+constexpr base::TimeDelta LoopbackStream::kCaptureDelay;
+
+LoopbackStream::LoopbackStream(
+    CreatedCallback created_callback,
+    BindingLostCallback binding_lost_callback,
+    scoped_refptr<base::SequencedTaskRunner> flow_task_runner,
+    media::mojom::AudioInputStreamRequest request,
+    media::mojom::AudioInputStreamClientPtr client,
+    media::mojom::AudioInputStreamObserverPtr observer,
+    const media::AudioParameters& params,
+    uint32_t shared_memory_count,
+    GroupCoordinator* coordinator,
+    const base::UnguessableToken& group_id)
+    : binding_lost_callback_(std::move(binding_lost_callback)),
+      binding_(this, std::move(request)),
+      client_(std::move(client)),
+      observer_(std::move(observer)),
+      coordinator_(coordinator),
+      group_id_(group_id),
+      network_(nullptr, base::OnTaskRunnerDeleter(flow_task_runner)),
+      weak_factory_(this) {
+  DCHECK(coordinator_);
+
+  // Generate an error and shut down automatically whenever any of the mojo
+  // bindings is closed.
+  binding_.set_connection_error_handler(
+      base::BindOnce(&LoopbackStream::OnError, base::Unretained(this)));
+  client_.set_connection_error_handler(
+      base::BindOnce(&LoopbackStream::OnError, base::Unretained(this)));
+  observer_.set_connection_error_handler(
+      base::BindOnce(&LoopbackStream::OnError, base::Unretained(this)));
+
+  // As of this writing, only machines older than about 10 years won't be able
+  // to produce high-resolution timestamps. In order to avoid adding extra
+  // complexity to the implementation, simply refuse to operate without that
+  // basic level of hardware support.
+  //
+  // Construct the components of the AudioDataPipe, for delivering the data to
+  // the consumer. If successful, create the FlowNetwork too.
+  if (base::TimeTicks::IsHighResolution()) {
+    base::CancelableSyncSocket foreign_socket;
+    std::unique_ptr<media::AudioInputSyncWriter> writer =
+        media::AudioInputSyncWriter::Create(
+            base::BindRepeating(
+                [](const std::string& message) { VLOG(1) << message; }),
+            shared_memory_count, params, &foreign_socket);
+    if (writer) {
+      const base::SharedMemory* memory = writer->shared_memory();
+      base::SharedMemoryHandle foreign_memory_handle =
+          memory->GetReadOnlyHandle();
+      mojo::ScopedSharedBufferHandle buffer_handle;
+      mojo::ScopedHandle socket_handle;
+      if (base::SharedMemory::IsHandleValid(foreign_memory_handle)) {
+        buffer_handle = mojo::WrapSharedMemoryHandle(
+            foreign_memory_handle, memory->requested_size(),
+            mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly);
+        socket_handle = mojo::WrapPlatformFile(foreign_socket.Release());
+        if (buffer_handle.is_valid() && socket_handle.is_valid()) {
+          std::move(created_callback)
+              .Run({base::in_place, std::move(buffer_handle),
+                    std::move(socket_handle)});
+          network_.reset(new FlowNetwork(std::move(flow_task_runner), params,
+                                         std::move(writer)));
+          return;  // Success!
+        }
+      }
+    }
+  } else /* if (!base::TimeTicks::IsHighResolution()) */ {
+    LOG(ERROR) << "Refusing to start loop-back because this machine cannot "
+                  "provide high-resolution timestamps.";
+  }
+
+  // If this point is reached, either the TimeTicks clock is not high resolution
+  // or one or more AudioDataPipe components failed to initialize. Report the
+  // error.
+  std::move(created_callback).Run(nullptr);
+  OnError();
+}
+
+LoopbackStream::~LoopbackStream() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (network_) {
+    if (network_->is_started()) {
+      coordinator_->RemoveObserver(group_id_, this);
+      for (GroupMember* member : coordinator_->GetCurrentMembers(group_id_)) {
+        OnMemberLeftGroup(member);
+      }
+    }
+    DCHECK(snoopers_.empty());
+  }
+}
+
+void LoopbackStream::Record() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!network_ || network_->is_started()) {
+    return;
+  }
+
+  // Begin snooping on all group members. This will set up the mixer network
+  // and begin accumulating audio data in the Snoopers' buffers.
+  DCHECK(snoopers_.empty());
+  for (GroupMember* member : coordinator_->GetCurrentMembers(group_id_)) {
+    OnMemberJoinedGroup(member);
+  }
+  coordinator_->AddObserver(group_id_, this);
+
+  // Start the data flow.
+  network_->Start();
+
+  if (observer_) {
+    observer_->DidStartRecording();
+  }
+}
+
+void LoopbackStream::SetVolume(double volume) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!std::isfinite(volume) || volume < 0.0) {
+    mojo::ReportBadMessage("Invalid volume");
+    OnError();
+    return;
+  }
+
+  if (network_) {
+    network_->SetVolume(std::min(volume, kMaxVolume));
+  }
+}
+
+void LoopbackStream::OnMemberJoinedGroup(GroupMember* member) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!network_) {
+    return;
+  }
+
+  const media::AudioParameters& input_params = member->GetAudioParameters();
+  const auto emplace_result = snoopers_.emplace(
+      std::piecewise_construct, std::forward_as_tuple(member),
+      std::forward_as_tuple(input_params, network_->output_params()));
+  DCHECK(emplace_result.second);  // There was no pre-existing map entry.
+  SnooperNode* const snooper = &(emplace_result.first->second);
+  member->StartSnooping(snooper);
+  network_->AddInput(snooper);
+}
+
+void LoopbackStream::OnMemberLeftGroup(GroupMember* member) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!network_) {
+    return;
+  }
+
+  const auto snoop_it = snoopers_.find(member);
+  DCHECK(snoop_it != snoopers_.end());
+  SnooperNode* const snooper = &(snoop_it->second);
+  member->StopSnooping(snooper);
+  network_->RemoveInput(snooper);
+  snoopers_.erase(snoop_it);
+}
+
+void LoopbackStream::OnError() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!binding_lost_callback_) {
+    return;  // OnError() was already called.
+  }
+
+  binding_.Close();
+  if (client_) {
+    client_->OnError();
+    client_.reset();
+  }
+  observer_.reset();
+
+  // Post a task to run the BindingLostCallback, since this method can be called
+  // from the constructor.
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](base::WeakPtr<LoopbackStream> weak_self,
+             BindingLostCallback callback) {
+            if (auto* self = weak_self.get()) {
+              std::move(callback).Run(self);
+            }
+          },
+          weak_factory_.GetWeakPtr(), std::move(binding_lost_callback_)));
+
+  // No need to shut down anything else, as the destructor will run soon and
+  // take care of the rest.
+}
+
+LoopbackStream::FlowNetwork::FlowNetwork(
+    scoped_refptr<base::SequencedTaskRunner> flow_task_runner,
+    const media::AudioParameters& output_params,
+    std::unique_ptr<media::AudioInputSyncWriter> writer)
+    : clock_(base::DefaultTickClock::GetInstance()),
+      flow_task_runner_(flow_task_runner),
+      output_params_(output_params),
+      writer_(std::move(writer)),
+      mix_bus_(media::AudioBus::Create(output_params_)) {}
+
+void LoopbackStream::FlowNetwork::AddInput(SnooperNode* node) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(control_sequence_);
+
+  base::AutoLock scoped_lock(lock_);
+  DCHECK(!base::ContainsValue(inputs_, node));
+  inputs_.push_back(node);
+}
+
+void LoopbackStream::FlowNetwork::RemoveInput(SnooperNode* node) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(control_sequence_);
+
+  base::AutoLock scoped_lock(lock_);
+  const auto it = std::find(inputs_.begin(), inputs_.end(), node);
+  DCHECK(it != inputs_.end());
+  inputs_.erase(it);
+}
+
+void LoopbackStream::FlowNetwork::SetVolume(double volume) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(control_sequence_);
+
+  base::AutoLock scoped_lock(lock_);
+  volume_ = volume;
+}
+
+void LoopbackStream::FlowNetwork::Start() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(control_sequence_);
+  DCHECK(!is_started());
+
+  timer_.emplace(clock_);
+  timer_->SetTaskRunner(flow_task_runner_);
+  // Note: GenerateMoreAudio() will schedule the timer.
+
+  first_generate_time_ = clock_->NowTicks();
+  frames_elapsed_ = 0;
+  next_generate_time_ = first_generate_time_;
+
+  flow_task_runner_->PostTask(
+      FROM_HERE,
+      // Unretained is safe because the destructor will always be invoked from a
+      // task that runs afterwards.
+      base::BindOnce(&FlowNetwork::GenerateMoreAudio, base::Unretained(this)));
+}
+
+LoopbackStream::FlowNetwork::~FlowNetwork() {
+  DCHECK(flow_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(inputs_.empty());
+}
+
+void LoopbackStream::FlowNetwork::GenerateMoreAudio() {
+  DCHECK(flow_task_runner_->RunsTasksInCurrentSequence());
+
+  // Always generate audio from the recent past, to prevent buffer underruns
+  // in the inputs.
+  const base::TimeTicks delayed_capture_time =
+      next_generate_time_ - kCaptureDelay;
+
+  // Drive the audio flows from the SnooperNodes and produce the single result
+  // stream. Hold the lock during this part of the process to prevent any of the
+  // control methods from altering the configuration of the network.
+  double output_volume;
+  {
+    base::AutoLock scoped_lock(lock_);
+    output_volume = volume_;
+
+    // Render the audio from each input, apply this stream's volume setting by
+    // scaling the data, then mix it all together to form a single audio
+    // signal. If there are no snoopers, just render silence.
+    auto it = inputs_.begin();
+    if (it == inputs_.end()) {
+      mix_bus_->Zero();
+    } else {
+      // Render the first input's signal directly into |mix_bus_|.
+      (*it)->Render(delayed_capture_time, mix_bus_.get());
+      mix_bus_->Scale(volume_);
+
+      // Render each successive input's signal into |transfer_bus_|, and then
+      // mix it into |mix_bus_|.
+      ++it;
+      if (it != inputs_.end()) {
+        if (!transfer_bus_) {
+          transfer_bus_ = media::AudioBus::Create(output_params_);
+        }
+        do {
+          (*it)->Render(delayed_capture_time, transfer_bus_.get());
+          for (int ch = 0; ch < transfer_bus_->channels(); ++ch) {
+            media::vector_math::FMAC(transfer_bus_->channel(ch), volume_,
+                                     transfer_bus_->frames(),
+                                     mix_bus_->channel(ch));
+          }
+          ++it;
+        } while (it != inputs_.end());
+      }
+    }
+  }
+
+  // Insert the result into the AudioDataPipe.
+  writer_->Write(mix_bus_.get(), output_volume, false, delayed_capture_time);
+
+  // Determine when to generate more audio again. This is done by advancing the
+  // frame count by one interval's worth, then computing the TimeTicks
+  // corresponding to the new frame count. Also, check the clock to detect when
+  // the user's machine is overloaded and the output needs to skip forward one
+  // or more intervals.
+  const int frames_per_buffer = mix_bus_->frames();
+  frames_elapsed_ += frames_per_buffer;
+  const base::TimeTicks now = clock_->NowTicks();
+  const int64_t required_frames_elapsed =
+      (now - first_generate_time_).InMicroseconds() *
+      output_params_.sample_rate() / base::Time::kMicrosecondsPerSecond;
+  if (frames_elapsed_ < required_frames_elapsed) {
+    // Audio generation has fallen behind. Skip ahead to the next interval.
+    frames_elapsed_ = ((required_frames_elapsed + frames_per_buffer - 1) /
+                       frames_per_buffer) *
+                      frames_per_buffer;
+  }
+  next_generate_time_ =
+      first_generate_time_ +
+      base::TimeDelta::FromMicroseconds(frames_elapsed_ *
+                                        base::Time::kMicrosecondsPerSecond /
+                                        output_params_.sample_rate());
+
+  // Use the OneShotTimer to call this method again at the desired time.
+  DCHECK_GE(next_generate_time_ - now, base::TimeDelta());
+  timer_->Start(FROM_HERE, next_generate_time_ - now, this,
+                &FlowNetwork::GenerateMoreAudio);
+}
+
+}  // namespace audio
diff --git a/services/audio/loopback_stream.h b/services/audio/loopback_stream.h
new file mode 100644
index 0000000..82f9f6c6
--- /dev/null
+++ b/services/audio/loopback_stream.h
@@ -0,0 +1,245 @@
+// Copyright 2018 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 SERVICES_AUDIO_LOOPBACK_STREAM_H_
+#define SERVICES_AUDIO_LOOPBACK_STREAM_H_
+
+#include <map>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/sequence_checker.h"
+#include "base/sequenced_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "base/unguessable_token.h"
+#include "media/audio/audio_input_controller.h"
+#include "media/audio/audio_input_sync_writer.h"
+#include "media/base/audio_parameters.h"
+#include "media/mojo/interfaces/audio_data_pipe.mojom.h"
+#include "media/mojo/interfaces/audio_input_stream.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/audio/group_coordinator.h"
+#include "services/audio/group_member.h"
+#include "services/audio/snooper_node.h"
+
+namespace base {
+class TickClock;
+}  // namespace base
+
+namespace media {
+class AudioBus;
+}  // namespace media
+
+namespace audio {
+
+// An AudioInputStream that provides the result of looping-back and
+// mixing-together all current and future audio output streams in the same
+// group. The loopback re-mixes the audio, if necessary, so that the resulting
+// data stream's format matches the required AudioParameters.
+//
+// This is organized in three main components: 1) The LoopbackStream itself acts
+// as a "shell" that manages mojo bindings and creates/controls the other
+// components. 2) One or more SnooperNodes that buffer input data for each
+// source OutputStream and format-convert it. 3) A "flow network" that runs via
+// a different task runner, to take all the audio collected in the SnooperNodes
+// and mix it into a single data stream.
+class LoopbackStream : public media::mojom::AudioInputStream,
+                       public GroupCoordinator::Observer {
+ public:
+  using CreatedCallback =
+      base::OnceCallback<void(media::mojom::AudioDataPipePtr)>;
+  using BindingLostCallback = base::OnceCallback<void(LoopbackStream*)>;
+
+  LoopbackStream(CreatedCallback created_callback,
+                 BindingLostCallback binding_lost_callback,
+                 scoped_refptr<base::SequencedTaskRunner> flow_task_runner,
+                 media::mojom::AudioInputStreamRequest request,
+                 media::mojom::AudioInputStreamClientPtr client,
+                 media::mojom::AudioInputStreamObserverPtr observer,
+                 const media::AudioParameters& params,
+                 uint32_t shared_memory_count,
+                 GroupCoordinator* coordinator,
+                 const base::UnguessableToken& group_id);
+
+  ~LoopbackStream() final;
+
+  bool is_recording() const { return network_ && network_->is_started(); }
+
+  // media::mojom::AudioInputStream implementation.
+  void Record() final;
+  void SetVolume(double volume) final;
+
+  // GroupCoordinator::Observer implementation. When a member joins a group, a
+  // SnooperNode is created for it, and a loopback flow from GroupMember →
+  // SnooperNode → FlowNetwork is built-up.
+  void OnMemberJoinedGroup(GroupMember* member) final;
+  void OnMemberLeftGroup(GroupMember* member) final;
+
+  // Overrides for unit testing. These must be called before Record().
+  void set_clock_for_testing(const base::TickClock* clock) {
+    network_->set_clock_for_testing(clock);
+  }
+  void set_sync_writer_for_testing(
+      std::unique_ptr<media::AudioInputController::SyncWriter> writer) {
+    network_->set_writer_for_testing(std::move(writer));
+  }
+
+  // Generally, a volume of 1.0 should be the maximum possible. However, there
+  // are cases where requests to amplify are made by specifying values higher
+  // than 1.0.
+  static constexpr double kMaxVolume = 2.0;
+
+  // The amount of time in the past from which to capture the audio. The audio
+  // recorded from each GroupMember is being generated with a target playout
+  // time in the near future (usually 1 to 20 ms). To avoid underflow,
+  // LoopbackStream fetches the audio from a position in the recent past.
+  static constexpr base::TimeDelta kCaptureDelay =
+      base::TimeDelta::FromMilliseconds(20);
+
+ private:
+  // Drives all audio flows, re-mixing the audio from multiple SnooperNodes into
+  // a single audio stream. This class mainly operates on a separate task runner
+  // from LoopbackStream and can only be destroyed by scheduling it to occur on
+  // that same task runner.
+  class FlowNetwork {
+   public:
+    FlowNetwork(scoped_refptr<base::SequencedTaskRunner> flow_task_runner,
+                const media::AudioParameters& output_params,
+                std::unique_ptr<media::AudioInputSyncWriter> writer);
+
+    // These must be called to override the Clock/SyncWriter before Start().
+    void set_clock_for_testing(const base::TickClock* clock) { clock_ = clock; }
+    void set_writer_for_testing(
+        std::unique_ptr<media::AudioInputController::SyncWriter> writer) {
+      writer_ = std::move(writer);
+    }
+
+    bool is_started() const {
+      DCHECK_CALLED_ON_VALID_SEQUENCE(control_sequence_);
+      return !!timer_;
+    }
+
+    const media::AudioParameters& output_params() const {
+      return output_params_;
+    }
+
+    // Add/Remove an input into this flow network. These may be called at any
+    // time, before or after Start(). All inputs must be removed before the
+    // FlowNetwork is scheduled for destruction.
+    void AddInput(SnooperNode* node);
+    void RemoveInput(SnooperNode* node);
+
+    // This may be called at any time, before or after Start(), to change the
+    // volume setting.
+    void SetVolume(double volume);
+
+    // Start generating audio data. This must only be called once, and there is
+    // no "stop" until destruction time.
+    void Start();
+
+   private:
+    // Since this class guarantees its destructor will be called via the flow
+    // task runner, and destruction is carried out only by base::DeleteHelper,
+    // make the destructor is private.
+    friend class base::DeleteHelper<FlowNetwork>;
+    ~FlowNetwork();
+
+    // Called periodically via the audio flow task runner to drive all the audio
+    // flows from the SnooperNodes, mix them together, and output to the
+    // AudioDataPipe. Each call schedules the next one until the |run_state_|
+    // becomes stopped.
+    void GenerateMoreAudio();
+
+    const base::TickClock* clock_;
+
+    // Task runner that calls GenerateMoreAudio() to drive all the audio data
+    // flows.
+    const scoped_refptr<base::SequencedTaskRunner> flow_task_runner_;
+
+    // The audio parameters of the output.
+    const media::AudioParameters output_params_;
+
+    // Destination for the output of this FlowNetwork.
+    std::unique_ptr<media::AudioInputController::SyncWriter> writer_;
+
+    // Ensures thread-safe access to changing the |inputs_| and |volume_| while
+    // running.
+    base::Lock lock_;
+
+    // The input nodes.
+    std::vector<SnooperNode*> inputs_;  // Guarded by |lock_|.
+
+    // Current stream volume. The audio output from this FlowNetwork is scaled
+    // by this amount during mixing.
+    double volume_ = 1.0;  // Guarded by |lock_|.
+
+    // This is set once Start() is called, and lives until this FlowNetwork is
+    // destroyed. It is used to schedule cancelable tasks run by the
+    // |flow_task_runner_|.
+    base::Optional<base::OneShotTimer> timer_;
+
+    // These are used to compute when the |timer_| fires and calls
+    // GenerateMoreAudio(). They ensure that each timer task is scheduled to
+    // fire with a delay that accounted for how much time was spent processing.
+    base::TimeTicks first_generate_time_;
+    int64_t frames_elapsed_ = 0;
+    base::TimeTicks next_generate_time_;
+
+    // Used to transfer the audio from each SnooperNode and mix them into a
+    // single audio signal. |transfer_bus_| is only allocated when first needed,
+    // but |mix_bus_| is allocated in the constructor because it is always
+    // needed.
+    std::unique_ptr<media::AudioBus> transfer_bus_;
+    const std::unique_ptr<media::AudioBus> mix_bus_;
+
+    SEQUENCE_CHECKER(control_sequence_);
+
+    DISALLOW_COPY_AND_ASSIGN(FlowNetwork);
+  };
+
+  // Reports a fatal error to the client, and then runs the BindingLostCallback.
+  void OnError();
+
+  // Run when any of |binding_|, |client_|, or |observer_| are closed. This
+  // callback is generally used to automatically terminate this LoopbackStream.
+  BindingLostCallback binding_lost_callback_;
+
+  // Mojo bindings. If any of these is closed, the LoopbackStream will call
+  // OnError(), which will run the |binding_lost_callback_|.
+  mojo::Binding<media::mojom::AudioInputStream> binding_;
+  media::mojom::AudioInputStreamClientPtr client_;
+  media::mojom::AudioInputStreamObserverPtr observer_;
+
+  // Used for identifying group members and snooping on their audio data flow.
+  GroupCoordinator* const coordinator_;
+  const base::UnguessableToken group_id_;
+
+  // The snoopers associated with each group member. This is not a flat_map
+  // because SnooperNodes cannot move around in memory while in operation.
+  std::map<GroupMember*, SnooperNode> snoopers_;
+
+  // The flow network that generates the single loopback result stream. It is
+  // owned by LoopbackStream, but it's destruction must be carried out by the
+  // flow task runner. This is never null, unless the system cannot support
+  // loopback (see constructor definition comments).
+  std::unique_ptr<FlowNetwork, base::OnTaskRunnerDeleter> network_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  base::WeakPtrFactory<LoopbackStream> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoopbackStream);
+};
+
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_LOOPBACK_STREAM_H_
diff --git a/services/audio/loopback_stream_unittest.cc b/services/audio/loopback_stream_unittest.cc
new file mode 100644
index 0000000..2000626
--- /dev/null
+++ b/services/audio/loopback_stream_unittest.cc
@@ -0,0 +1,417 @@
+// Copyright 2018 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 "services/audio/loopback_stream.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstdint>
+#include <memory>
+
+#include "base/containers/unique_ptr_adapters.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/unguessable_token.h"
+#include "media/base/audio_parameters.h"
+#include "media/base/audio_timestamp_helper.h"
+#include "media/base/channel_layout.h"
+#include "services/audio/group_coordinator.h"
+#include "services/audio/group_member.h"
+#include "services/audio/test/fake_consumer.h"
+#include "services/audio/test/fake_group_member.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Mock;
+using testing::NiceMock;
+using testing::StrictMock;
+
+namespace audio {
+namespace {
+
+// Volume settings for the FakeGroupMember (source) and LoopbackStream.
+constexpr double kSnoopVolume = 0.25;
+constexpr double kLoopbackVolume = 0.5;
+
+// Piano key frequencies.
+constexpr double kMiddleAFreq = 440;
+constexpr double kMiddleCFreq = 261.626;
+
+// Audio buffer duration.
+constexpr base::TimeDelta kBufferDuration =
+    base::TimeDelta::FromMilliseconds(10);
+
+// Local audio output delay.
+constexpr base::TimeDelta kDelayUntilOutput =
+    base::TimeDelta::FromMilliseconds(20);
+
+// The amount of audio signal to record each time PumpAudioAndTakeNewRecording()
+// is called.
+constexpr base::TimeDelta kTestRecordingDuration =
+    base::TimeDelta::FromMilliseconds(250);
+
+const media::AudioParameters& GetLoopbackStreamParams() {
+  // 48 kHz, 2-channel audio, with 10 ms buffers.
+  static const media::AudioParameters params(
+      media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+      media::CHANNEL_LAYOUT_STEREO, 48000, 480);
+  return params;
+}
+
+class MockClientAndObserver : public media::mojom::AudioInputStreamClient,
+                              public media::mojom::AudioInputStreamObserver {
+ public:
+  MockClientAndObserver() : client_binding_(this), observer_binding_(this) {}
+
+  ~MockClientAndObserver() override = default;
+
+  void Bind(media::mojom::AudioInputStreamClientRequest client_request,
+            media::mojom::AudioInputStreamObserverRequest observer_request) {
+    client_binding_.Bind(std::move(client_request));
+    observer_binding_.Bind(std::move(observer_request));
+  }
+
+  void CloseClientBinding() { client_binding_.Close(); }
+  void CloseObserverBinding() { observer_binding_.Close(); }
+
+  MOCK_METHOD0(OnError, void());
+  MOCK_METHOD0(DidStartRecording, void());
+  void OnMutedStateChanged(bool) override { NOTREACHED(); }
+
+ private:
+  mojo::Binding<media::mojom::AudioInputStreamClient> client_binding_;
+  mojo::Binding<media::mojom::AudioInputStreamObserver> observer_binding_;
+};
+
+// Subclass of FakeConsumer that adapts the SyncWriter interface to allow the
+// tests to record and analyze the audio data from the LoopbackStream.
+class FakeSyncWriter : public FakeConsumer,
+                       public media::AudioInputController::SyncWriter {
+ public:
+  FakeSyncWriter(int channels, int sample_rate)
+      : FakeConsumer(channels, sample_rate) {}
+
+  ~FakeSyncWriter() override = default;
+
+  void Clear() {
+    FakeConsumer::Clear();
+    last_capture_time_ = base::TimeTicks();
+  }
+
+  // media::AudioInputController::SyncWriter implementation.
+  void Write(const media::AudioBus* data,
+             double volume,
+             bool key_pressed,
+             base::TimeTicks capture_time) final {
+    FakeConsumer::Consume(*data);
+
+    // Capture times should be monotonically increasing.
+    if (!last_capture_time_.is_null()) {
+      CHECK_LT(last_capture_time_, capture_time);
+    }
+    last_capture_time_ = capture_time;
+  }
+
+  void Close() final {}
+
+  base::TimeTicks last_capture_time_;
+};
+
+class LoopbackStreamTest : public testing::Test {
+ public:
+  LoopbackStreamTest()
+      : task_runner_(base::MakeRefCounted<base::TestMockTimeTaskRunner>(
+            base::Time(),
+            // The starting TimeTicks value is "huge" to ensure time
+            // calculations are being tested for overflow cases.
+            base::TimeTicks() +
+                base::TimeDelta::FromMicroseconds(INT64_C(1) << 62),
+            base::TestMockTimeTaskRunner::Type::kBoundToThread)),
+        group_id_(base::UnguessableToken::Create()) {}
+
+  ~LoopbackStreamTest() override = default;
+
+  void TearDown() override {
+    stream_ = nullptr;
+
+    for (const auto& source : sources_) {
+      coordinator_.UnregisterGroupMember(source.get());
+    }
+    sources_.clear();
+
+    task_runner_->FastForwardUntilNoTasksRemain();
+  }
+
+  MockClientAndObserver* client() { return &client_; }
+  LoopbackStream* stream() { return stream_.get(); }
+  FakeSyncWriter* consumer() { return consumer_; }
+
+  void RunMojoTasks() { task_runner_->RunUntilIdle(); }
+
+  FakeGroupMember* AddSource(int channels, int sample_rate) {
+    sources_.emplace_back(std::make_unique<FakeGroupMember>(
+        group_id_,
+        media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+                               media::GuessChannelLayout(channels), sample_rate,
+                               (sample_rate * kBufferDuration) /
+                                   base::TimeDelta::FromSeconds(1))));
+    coordinator_.RegisterGroupMember(sources_.back().get());
+    return sources_.back().get();
+  }
+
+  void RemoveSource(FakeGroupMember* source) {
+    const auto it = std::find_if(sources_.begin(), sources_.end(),
+                                 base::MatchesUniquePtr(source));
+    if (it != sources_.end()) {
+      coordinator_.UnregisterGroupMember(source);
+      sources_.erase(it);
+    }
+  }
+
+  void CreateLoopbackStream() {
+    CHECK(!stream_);
+
+    media::mojom::AudioInputStreamClientPtr client_ptr;
+    media::mojom::AudioInputStreamObserverPtr observer_ptr;
+    client_.Bind(mojo::MakeRequest(&client_ptr),
+                 mojo::MakeRequest(&observer_ptr));
+
+    stream_ = std::make_unique<LoopbackStream>(
+        base::BindOnce([](media::mojom::AudioDataPipePtr pipe) {
+          EXPECT_TRUE(pipe->shared_memory.is_valid());
+          EXPECT_TRUE(pipe->socket.is_valid());
+        }),
+        base::BindOnce([](LoopbackStreamTest* self,
+                          LoopbackStream* stream) { self->stream_ = nullptr; },
+                       this),
+        task_runner_, mojo::MakeRequest(&input_stream_ptr_),
+        std::move(client_ptr), std::move(observer_ptr),
+        GetLoopbackStreamParams(),
+        // The following argument is the |shared_memory_count|, which does not
+        // matter because the SyncWriter will be overridden with FakeSyncWriter
+        // below.
+        1, &coordinator_, group_id_);
+
+    // Override the clock used by the LoopbackStream so that everything is
+    // single-threaded and synchronized with the driving code in these tests.
+    stream_->set_clock_for_testing(task_runner_->GetMockTickClock());
+
+    // Redirect the output of the LoopbackStream to a FakeSyncWriter.
+    // LoopbackStream takes ownership of the FakeSyncWriter.
+    auto consumer = std::make_unique<FakeSyncWriter>(
+        GetLoopbackStreamParams().channels(),
+        GetLoopbackStreamParams().sample_rate());
+    CHECK(!consumer_);
+    consumer_ = consumer.get();
+    stream_->set_sync_writer_for_testing(std::move(consumer));
+
+    // Set the volume for the LoopbackStream.
+    input_stream_ptr_->SetVolume(kLoopbackVolume);
+
+    // Allow all pending mojo tasks for all of the above to run and propagate
+    // state.
+    RunMojoTasks();
+
+    ASSERT_TRUE(input_stream_ptr_);
+  }
+
+  void StartLoopbackRecording() {
+    ASSERT_EQ(0, consumer_->GetRecordedFrameCount());
+    input_stream_ptr_->Record();
+    RunMojoTasks();
+  }
+
+  void SetLoopbackVolume(double volume) {
+    input_stream_ptr_->SetVolume(volume);
+    RunMojoTasks();
+  }
+
+  void PumpAudioAndTakeNewRecording() {
+    consumer_->Clear();
+
+    const int min_frames_to_record = media::AudioTimestampHelper::TimeToFrames(
+        kTestRecordingDuration, GetLoopbackStreamParams().sample_rate());
+    do {
+      // Render audio meant for local output at some point in the near
+      // future.
+      const base::TimeTicks output_timestamp =
+          task_runner_->NowTicks() + kDelayUntilOutput;
+      for (const auto& source : sources_) {
+        source->RenderMoreAudio(output_timestamp);
+      }
+
+      // Move the task runner forward, which will cause the FlowNetwork's
+      // delayed tasks to run, which will generate output for the consumer.
+      task_runner_->FastForwardBy(kBufferDuration);
+    } while (consumer_->GetRecordedFrameCount() < min_frames_to_record);
+  }
+
+  void CloseInputStreamPtr() {
+    input_stream_ptr_.reset();
+    RunMojoTasks();
+  }
+
+ private:
+  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+  GroupCoordinator coordinator_;
+  const base::UnguessableToken group_id_;
+  std::vector<std::unique_ptr<FakeGroupMember>> sources_;
+  NiceMock<MockClientAndObserver> client_;
+  std::unique_ptr<LoopbackStream> stream_;
+  FakeSyncWriter* consumer_ = nullptr;  // Owned by |stream_|.
+
+  media::mojom::AudioInputStreamPtr input_stream_ptr_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoopbackStreamTest);
+};
+
+TEST_F(LoopbackStreamTest, ShutsDownStreamWhenInterfacePtrIsClosed) {
+  CreateLoopbackStream();
+  EXPECT_CALL(*client(), DidStartRecording());
+  StartLoopbackRecording();
+  PumpAudioAndTakeNewRecording();
+  EXPECT_CALL(*client(), OnError());
+  CloseInputStreamPtr();
+  EXPECT_FALSE(stream());
+  Mock::VerifyAndClearExpectations(client());
+}
+
+TEST_F(LoopbackStreamTest, ShutsDownStreamWhenClientBindingIsClosed) {
+  CreateLoopbackStream();
+  EXPECT_CALL(*client(), DidStartRecording());
+  StartLoopbackRecording();
+  PumpAudioAndTakeNewRecording();
+  // Note: Expect no call to client::OnError() because it is the client binding
+  // that is being closed and causing the error.
+  EXPECT_CALL(*client(), OnError()).Times(0);
+  client()->CloseClientBinding();
+  RunMojoTasks();
+  EXPECT_FALSE(stream());
+  Mock::VerifyAndClearExpectations(client());
+}
+
+TEST_F(LoopbackStreamTest, ShutsDownStreamWhenObserverBindingIsClosed) {
+  CreateLoopbackStream();
+  EXPECT_CALL(*client(), DidStartRecording());
+  StartLoopbackRecording();
+  PumpAudioAndTakeNewRecording();
+  EXPECT_CALL(*client(), OnError());
+  client()->CloseObserverBinding();
+  RunMojoTasks();
+  EXPECT_FALSE(stream());
+  Mock::VerifyAndClearExpectations(client());
+}
+
+TEST_F(LoopbackStreamTest, ProducesSilenceWhenNoMembersArePresent) {
+  CreateLoopbackStream();
+  EXPECT_CALL(*client(), DidStartRecording());
+  StartLoopbackRecording();
+  PumpAudioAndTakeNewRecording();
+  for (int ch = 0; ch < GetLoopbackStreamParams().channels(); ++ch) {
+    SCOPED_TRACE(testing::Message() << "ch=" << ch);
+    EXPECT_TRUE(consumer()->IsSilent(ch));
+  }
+}
+
+// Syntatic sugar to confirm a tone exists and its amplitude matches
+// expectations.
+#define EXPECT_TONE(ch, frequency, expected_amplitude)                     \
+  {                                                                        \
+    SCOPED_TRACE(testing::Message() << "ch=" << ch);                       \
+    const double amplitude = consumer()->ComputeAmplitudeAt(               \
+        ch, frequency, consumer()->GetRecordedFrameCount());               \
+    VLOG(1) << "For ch=" << ch << ", amplitude at frequency=" << frequency \
+            << " is " << amplitude;                                        \
+    EXPECT_NEAR(expected_amplitude, amplitude, 0.01);                      \
+  }
+
+TEST_F(LoopbackStreamTest, ProducesAudioFromASingleSource) {
+  FakeGroupMember* const source = AddSource(1, 48000);  // Monaural, 48 kHz.
+  source->SetChannelTone(0, kMiddleAFreq);
+  source->SetVolume(kSnoopVolume);
+
+  CreateLoopbackStream();
+  EXPECT_CALL(*client(), DidStartRecording());
+  StartLoopbackRecording();
+  PumpAudioAndTakeNewRecording();
+
+  // Expect to have recorded middle-A in all of the loopback stream's channels.
+  for (int ch = 0; ch < GetLoopbackStreamParams().channels(); ++ch) {
+    EXPECT_TONE(ch, kMiddleAFreq, kSnoopVolume * kLoopbackVolume);
+  }
+}
+
+TEST_F(LoopbackStreamTest, ProducesAudioFromTwoSources) {
+  // Start the first source (of a middle-A note) before creating the loopback
+  // stream.
+  const int channels = GetLoopbackStreamParams().channels();
+  FakeGroupMember* const source1 = AddSource(channels, 48000);
+  source1->SetChannelTone(0, kMiddleAFreq);
+  source1->SetVolume(kSnoopVolume);
+
+  CreateLoopbackStream();
+  EXPECT_CALL(*client(), DidStartRecording());
+  StartLoopbackRecording();
+  PumpAudioAndTakeNewRecording();
+
+  // Start the second source (of a middle-C note) while the loopback stream is
+  // running. The second source has a different sample rate than the first.
+  FakeGroupMember* const source2 = AddSource(channels, 44100);
+  source2->SetChannelTone(1, kMiddleCFreq);
+  source2->SetVolume(kSnoopVolume);
+
+  PumpAudioAndTakeNewRecording();
+
+  // Expect to have recorded both middle-A and middle-C in all of the loopback
+  // stream's channels.
+  EXPECT_TONE(0, kMiddleAFreq, kSnoopVolume * kLoopbackVolume);
+  EXPECT_TONE(1, kMiddleCFreq, kSnoopVolume * kLoopbackVolume);
+
+  // Switch the channels containig the tone in both sources, and expect to see
+  // the tones have switched channels in the loopback output.
+  source1->SetChannelTone(0, 0.0);
+  source1->SetChannelTone(1, kMiddleAFreq);
+  source2->SetChannelTone(0, kMiddleCFreq);
+  source2->SetChannelTone(1, 0.0);
+  PumpAudioAndTakeNewRecording();
+  EXPECT_TONE(1, kMiddleAFreq, kSnoopVolume * kLoopbackVolume);
+  EXPECT_TONE(0, kMiddleCFreq, kSnoopVolume * kLoopbackVolume);
+}
+
+TEST_F(LoopbackStreamTest, AudioChangesVolume) {
+  FakeGroupMember* const source = AddSource(1, 48000);  // Monaural, 48 kHz.
+  source->SetChannelTone(0, kMiddleAFreq);
+  source->SetVolume(kSnoopVolume);
+
+  CreateLoopbackStream();
+  StartLoopbackRecording();
+  PumpAudioAndTakeNewRecording();
+
+  // Record and check the amplitude at the default volume settings.
+  double expected_amplitude = kSnoopVolume * kLoopbackVolume;
+  for (int ch = 0; ch < GetLoopbackStreamParams().channels(); ++ch) {
+    EXPECT_TONE(ch, kMiddleAFreq, expected_amplitude);
+  }
+
+  // Double the volume of the source and expect the output to have also doubled.
+  source->SetVolume(kSnoopVolume * 2);
+  PumpAudioAndTakeNewRecording();
+  expected_amplitude *= 2;
+  for (int ch = 0; ch < GetLoopbackStreamParams().channels(); ++ch) {
+    EXPECT_TONE(ch, kMiddleAFreq, expected_amplitude);
+  }
+
+  // Drop the LoopbackStream volume by 1/3 and expect the output to also have
+  // dropped by 1/3.
+  SetLoopbackVolume(kLoopbackVolume / 3);
+  PumpAudioAndTakeNewRecording();
+  expected_amplitude /= 3;
+  for (int ch = 0; ch < GetLoopbackStreamParams().channels(); ++ch) {
+    EXPECT_TONE(ch, kMiddleAFreq, expected_amplitude);
+  }
+}
+
+}  // namespace
+}  // namespace audio
diff --git a/services/audio/public/cpp/BUILD.gn b/services/audio/public/cpp/BUILD.gn
index c86efc1e..ea40a26 100644
--- a/services/audio/public/cpp/BUILD.gn
+++ b/services/audio/public/cpp/BUILD.gn
@@ -26,10 +26,16 @@
   testonly = true
 
   sources = [
+    "fake_stream_factory.cc",
+    "fake_stream_factory.h",
     "fake_system_info.cc",
     "fake_system_info.h",
   ]
 
+  deps = [
+    "//testing/gmock",
+  ]
+
   public_deps = [
     "//base",
     "//media",
diff --git a/services/audio/public/cpp/fake_stream_factory.cc b/services/audio/public/cpp/fake_stream_factory.cc
new file mode 100644
index 0000000..668dbbb
--- /dev/null
+++ b/services/audio/public/cpp/fake_stream_factory.cc
@@ -0,0 +1,12 @@
+// Copyright 2018 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 "services/audio/public/cpp/fake_stream_factory.h"
+
+namespace audio {
+
+FakeStreamFactory::FakeStreamFactory() : binding_(this) {}
+FakeStreamFactory::~FakeStreamFactory() = default;
+
+}  // namespace audio
diff --git a/services/audio/public/cpp/fake_stream_factory.h b/services/audio/public/cpp/fake_stream_factory.h
new file mode 100644
index 0000000..38d06e5c
--- /dev/null
+++ b/services/audio/public/cpp/fake_stream_factory.h
@@ -0,0 +1,53 @@
+// Copyright 2018 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 SERVICES_AUDIO_PUBLIC_CPP_FAKE_STREAM_FACTORY_H_
+#define SERVICES_AUDIO_PUBLIC_CPP_FAKE_STREAM_FACTORY_H_
+
+#include <string>
+
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/audio/public/mojom/stream_factory.mojom.h"
+
+namespace audio {
+
+class FakeStreamFactory : public mojom::StreamFactory {
+ public:
+  FakeStreamFactory();
+  ~FakeStreamFactory() override;
+
+  mojom::StreamFactoryPtr MakePtr() {
+    mojom::StreamFactoryPtr ptr;
+    binding_.Bind(mojo::MakeRequest(&ptr));
+    return ptr;
+  }
+
+  void CreateInputStream(media::mojom::AudioInputStreamRequest stream_request,
+                         media::mojom::AudioInputStreamClientPtr client,
+                         media::mojom::AudioInputStreamObserverPtr observer,
+                         media::mojom::AudioLogPtr log,
+                         const std::string& device_id,
+                         const media::AudioParameters& params,
+                         uint32_t shared_memory_count,
+                         bool enable_agc,
+                         mojo::ScopedSharedBufferHandle key_press_count_buffer,
+                         CreateInputStreamCallback created_callback) override {}
+  void CreateOutputStream(
+      media::mojom::AudioOutputStreamRequest stream_request,
+      media::mojom::AudioOutputStreamObserverAssociatedPtrInfo observer_info,
+      media::mojom::AudioLogPtr log,
+      const std::string& output_device_id,
+      const media::AudioParameters& params,
+      const base::UnguessableToken& group_id,
+      CreateOutputStreamCallback created_callback) override {}
+  void BindMuter(mojom::LocalMuterAssociatedRequest request,
+                 const base::UnguessableToken& group_id) override {}
+
+  mojo::Binding<mojom::StreamFactory> binding_;
+};
+
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_PUBLIC_CPP_FAKE_STREAM_FACTORY_H_
diff --git a/services/network/cors/preflight_controller.cc b/services/network/cors/preflight_controller.cc
index 53239f3..f161962 100644
--- a/services/network/cors/preflight_controller.cc
+++ b/services/network/cors/preflight_controller.cc
@@ -260,9 +260,8 @@
     // Preflight should not allow any redirect.
     FinalizeLoader();
 
-    // TODO(toyoshim): Define kDisallowedPreflightRedirect in a separate patch.
     std::move(completion_callback_)
-        .Run(CORSErrorStatus(mojom::CORSError::kPreflightInvalidStatus));
+        .Run(CORSErrorStatus(mojom::CORSError::kPreflightDisallowedRedirect));
 
     RemoveFromController();
     // |this| is deleted here.
diff --git a/services/network/public/mojom/cors.mojom b/services/network/public/mojom/cors.mojom
index 9de6bae..9b8b0732 100644
--- a/services/network/public/mojom/cors.mojom
+++ b/services/network/public/mojom/cors.mojom
@@ -37,10 +37,13 @@
   // header.
   kInvalidAllowCredentials,
 
-  // Preflight
+  // Preflight:
   // Failed to check HTTP response ok status in a CORS-preflight response.
   kPreflightInvalidStatus,
 
+  // Redirect is requested in CORS-preflight response, but not allowed.
+  kPreflightDisallowedRedirect,
+
   // Not allowed wildcard origin was found in Access-Control-Allow-Origin
   // CORS-preflight response header when the credentials mode is 'include'.
   kPreflightWildcardOriginNotAllowed,
diff --git a/services/shape_detection/android/java/src/org/chromium/shape_detection/FaceDetectionImplGmsCore.java b/services/shape_detection/android/java/src/org/chromium/shape_detection/FaceDetectionImplGmsCore.java
index a1eca5a..d29cb05 100644
--- a/services/shape_detection/android/java/src/org/chromium/shape_detection/FaceDetectionImplGmsCore.java
+++ b/services/shape_detection/android/java/src/org/chromium/shape_detection/FaceDetectionImplGmsCore.java
@@ -99,27 +99,33 @@
             for (int j = 0; j < landmarks.size(); j++) {
                 final Landmark landmark = landmarks.get(j);
                 final int landmarkType = landmark.getType();
-                if (landmarkType == Landmark.LEFT_EYE || landmarkType == Landmark.RIGHT_EYE
-                        || landmarkType == Landmark.BOTTOM_MOUTH) {
-                    org.chromium.shape_detection.mojom.Landmark mojoLandmark =
-                            new org.chromium.shape_detection.mojom.Landmark();
-                    mojoLandmark.locations = new org.chromium.gfx.mojom.PointF[1];
-                    mojoLandmark.locations[0] = new org.chromium.gfx.mojom.PointF();
-                    mojoLandmark.locations[0].x = landmark.getPosition().x;
-                    mojoLandmark.locations[0].y = landmark.getPosition().y;
-                    mojoLandmark.type = landmarkType == Landmark.BOTTOM_MOUTH ? LandmarkType.MOUTH
-                                                                              : LandmarkType.EYE;
-                    mojoLandmarks.add(mojoLandmark);
-
-                    if (landmarkType == Landmark.LEFT_EYE) {
-                        leftEyeIndex = j;
-                    } else if (landmarkType == Landmark.RIGHT_EYE) {
-                        rightEyeIndex = j;
-                    } else {
-                        assert landmarkType == Landmark.BOTTOM_MOUTH;
-                        bottomMouthIndex = j;
-                    }
+                if (landmarkType != Landmark.LEFT_EYE && landmarkType != Landmark.RIGHT_EYE
+                        && landmarkType != Landmark.BOTTOM_MOUTH
+                        && landmarkType != Landmark.NOSE_BASE) {
+                    continue;
                 }
+
+                org.chromium.shape_detection.mojom.Landmark mojoLandmark =
+                        new org.chromium.shape_detection.mojom.Landmark();
+                mojoLandmark.locations = new org.chromium.gfx.mojom.PointF[1];
+                mojoLandmark.locations[0] = new org.chromium.gfx.mojom.PointF();
+                mojoLandmark.locations[0].x = landmark.getPosition().x;
+                mojoLandmark.locations[0].y = landmark.getPosition().y;
+
+                if (landmarkType == Landmark.LEFT_EYE) {
+                    mojoLandmark.type = LandmarkType.EYE;
+                    leftEyeIndex = j;
+                } else if (landmarkType == Landmark.RIGHT_EYE) {
+                    mojoLandmark.type = LandmarkType.EYE;
+                    rightEyeIndex = j;
+                } else if (landmarkType == Landmark.BOTTOM_MOUTH) {
+                    mojoLandmark.type = LandmarkType.MOUTH;
+                    bottomMouthIndex = j;
+                } else {
+                    assert landmarkType == Landmark.NOSE_BASE;
+                    mojoLandmark.type = LandmarkType.NOSE;
+                }
+                mojoLandmarks.add(mojoLandmark);
             }
             faceArray[i].landmarks = mojoLandmarks.toArray(
                     new org.chromium.shape_detection.mojom.Landmark[mojoLandmarks.size()]);
diff --git a/services/shape_detection/android/javatests/src/org/chromium/shape_detection/FaceDetectionImplTest.java b/services/shape_detection/android/javatests/src/org/chromium/shape_detection/FaceDetectionImplTest.java
index 8e19603b..f57610a3 100644
--- a/services/shape_detection/android/javatests/src/org/chromium/shape_detection/FaceDetectionImplTest.java
+++ b/services/shape_detection/android/javatests/src/org/chromium/shape_detection/FaceDetectionImplTest.java
@@ -76,6 +76,8 @@
     private void detectSucceedsOnValidImage(DetectionProviderType api) {
         FaceDetectionResult[] results = detect(MONA_LISA_BITMAP, true, api);
         Assert.assertEquals(1, results.length);
+        Assert.assertEquals(
+                api == DetectionProviderType.GMS_CORE ? 4 : 0, results[0].landmarks.length);
         Assert.assertEquals(40.0, results[0].boundingBox.width, BOUNDING_BOX_SIZE_ERROR);
         Assert.assertEquals(40.0, results[0].boundingBox.height, BOUNDING_BOX_SIZE_ERROR);
         Assert.assertEquals(24.0, results[0].boundingBox.x, BOUNDING_BOX_POSITION_ERROR);
diff --git a/services/shape_detection/face_detection_impl_mac_unittest.mm b/services/shape_detection/face_detection_impl_mac_unittest.mm
index 1c507b7..57b5dc9 100644
--- a/services/shape_detection/face_detection_impl_mac_unittest.mm
+++ b/services/shape_detection/face_detection_impl_mac_unittest.mm
@@ -69,13 +69,13 @@
      base::Bind(&CreateFaceDetectorImplMac)},
     {true, 120, 120, "services/test/data/mona_lisa.jpg", 1, 3,
      base::Bind(&CreateFaceDetectorImplMac)},
-    {false, 120, 120, "services/test/data/mona_lisa.jpg", 1, 3,
+    {false, 120, 120, "services/test/data/mona_lisa.jpg", 1, 4,
      base::Bind(&CreateFaceDetectorImplMacVision)},
     {false, 240, 240, "services/test/data/the_beatles.jpg", 3, 3,
      base::Bind(&CreateFaceDetectorImplMac)},
     {true, 240, 240, "services/test/data/the_beatles.jpg", 3, 3,
      base::Bind(&CreateFaceDetectorImplMac)},
-    {false, 240, 240, "services/test/data/the_beatles.jpg", 4, 3,
+    {false, 240, 240, "services/test/data/the_beatles.jpg", 4, 4,
      base::Bind(&CreateFaceDetectorImplMacVision)},
 };
 
diff --git a/services/shape_detection/face_detection_impl_mac_vision.mm b/services/shape_detection/face_detection_impl_mac_vision.mm
index e36ebe8e..fd64af0 100644
--- a/services/shape_detection/face_detection_impl_mac_vision.mm
+++ b/services/shape_detection/face_detection_impl_mac_vision.mm
@@ -188,6 +188,10 @@
       face->landmarks.push_back(BuildLandmark(
           outerLips, mojom::LandmarkType::MOUTH, face->bounding_box));
     }
+    if (VNFaceLandmarkRegion2D* nose = observation.landmarks.nose) {
+      face->landmarks.push_back(
+          BuildLandmark(nose, mojom::LandmarkType::NOSE, face->bounding_box));
+    }
 
     results.push_back(std::move(face));
   }
diff --git a/services/shape_detection/public/mojom/facedetection.mojom b/services/shape_detection/public/mojom/facedetection.mojom
index 28afbb6..7075813 100644
--- a/services/shape_detection/public/mojom/facedetection.mojom
+++ b/services/shape_detection/public/mojom/facedetection.mojom
@@ -10,7 +10,7 @@
 import "ui/gfx/geometry/mojo/geometry.mojom";
 
 // https://wicg.github.io/shape-detection-api/#enumdef-landmarktype
-enum LandmarkType { MOUTH, EYE };
+enum LandmarkType { MOUTH, EYE, NOSE };
 
 // https://wicg.github.io/shape-detection-api/#dictdef-landmark
 struct Landmark {
diff --git a/services/ui/manifest.json b/services/ui/manifest.json
index faf5a19..8b1395c 100644
--- a/services/ui/manifest.json
+++ b/services/ui/manifest.json
@@ -12,10 +12,10 @@
         "app": [
           "discardable_memory::mojom::DiscardableSharedMemoryManager",
           "ui::mojom::Clipboard",
-          "ui::mojom::DisplayManager",
           "ui::mojom::Gpu",
           "ui::mojom::IMEDriver",
           "ui::mojom::InputDeviceServer",
+          "ui::mojom::ScreenProvider",
           "ui::mojom::WindowTreeFactory"
         ],
         "arc_manager" : [
@@ -64,12 +64,12 @@
           "display::mojom::NativeDisplayDelegate",
           "ui::mojom::AccessibilityManager",
           "ui::mojom::Clipboard",
-          "ui::mojom::DisplayManager",
           "ui::mojom::EventInjector",
           "ui::mojom::Gpu",
           "ui::mojom::IMEDriver",
           "ui::mojom::InputDeviceController",
           "ui::mojom::InputDeviceServer",
+          "ui::mojom::ScreenProvider",
           "ui::mojom::TouchDeviceServer",
           "ui::mojom::UserActivityMonitor",
           "ui::mojom::WindowManagerWindowTreeFactory"
diff --git a/services/ui/public/interfaces/BUILD.gn b/services/ui/public/interfaces/BUILD.gn
index a59fd14..a66b0e93 100644
--- a/services/ui/public/interfaces/BUILD.gn
+++ b/services/ui/public/interfaces/BUILD.gn
@@ -17,11 +17,11 @@
   sources = [
     "accessibility_manager.mojom",
     "clipboard.mojom",
-    "display_manager.mojom",
     "event_injector.mojom",
     "event_matcher.mojom",
     "gpu.mojom",
     "mus_constants.mojom",
+    "screen_provider.mojom",
     "user_activity_monitor.mojom",
     "video_detector.mojom",
     "window_manager.mojom",
diff --git a/services/ui/public/interfaces/display_manager.mojom b/services/ui/public/interfaces/screen_provider.mojom
similarity index 84%
rename from services/ui/public/interfaces/display_manager.mojom
rename to services/ui/public/interfaces/screen_provider.mojom
index 7e7b25e9..6b61cfb 100644
--- a/services/ui/public/interfaces/display_manager.mojom
+++ b/services/ui/public/interfaces/screen_provider.mojom
@@ -6,7 +6,7 @@
 
 import "services/ui/public/interfaces/window_manager_constants.mojom";
 
-interface DisplayManagerObserver {
+interface ScreenProviderObserver {
   // Sent when the observer is added as well as any time the set of displays
   // changes in any way. |displays| contains all known displays. If the system
   // that WS is running on has an integrated display, for example a laptop
@@ -18,8 +18,7 @@
                     int64 internal_display_id);
 };
 
-// TODO(jamescook): Rename to ScreenProvider.
-interface DisplayManager {
+interface ScreenProvider {
   // Adding an observer triggers a notification with the initial values.
-  AddObserver(DisplayManagerObserver observer);
+  AddObserver(ScreenProviderObserver observer);
 };
diff --git a/services/ui/service.cc b/services/ui/service.cc
index 02d62b0..ac4f3fac 100644
--- a/services/ui/service.cc
+++ b/services/ui/service.cc
@@ -121,7 +121,7 @@
 struct Service::PendingRequest {
   service_manager::BindSourceInfo source_info;
   std::unique_ptr<mojom::WindowTreeFactoryRequest> wtf_request;
-  std::unique_ptr<mojom::DisplayManagerRequest> dm_request;
+  std::unique_ptr<mojom::ScreenProviderRequest> screen_request;
 };
 
 Service::InitParams::InitParams() = default;
@@ -282,8 +282,8 @@
                           base::Unretained(this)));
   registry_with_source_info_.AddInterface<mojom::Clipboard>(base::BindRepeating(
       &Service::BindClipboardRequest, base::Unretained(this)));
-  registry_with_source_info_.AddInterface<mojom::DisplayManager>(
-      base::BindRepeating(&Service::BindDisplayManagerRequest,
+  registry_with_source_info_.AddInterface<mojom::ScreenProvider>(
+      base::BindRepeating(&Service::BindScreenProviderRequest,
                           base::Unretained(this)));
   registry_.AddInterface<mojom::IMERegistrar>(base::BindRepeating(
       &Service::BindIMERegistrarRequest, base::Unretained(this)));
@@ -349,7 +349,7 @@
       BindWindowTreeFactoryRequest(std::move(*request->wtf_request),
                                    request->source_info);
     } else {
-      BindDisplayManagerRequest(std::move(*request->dm_request),
+      BindScreenProviderRequest(std::move(*request->screen_request),
                                 request->source_info);
     }
   }
@@ -423,16 +423,16 @@
   clipboard_->AddBinding(std::move(request));
 }
 
-void Service::BindDisplayManagerRequest(
-    mojom::DisplayManagerRequest request,
+void Service::BindScreenProviderRequest(
+    mojom::ScreenProviderRequest request,
     const service_manager::BindSourceInfo& source_info) {
   // Wait for the DisplayManager to be configured before binding display
   // requests. Otherwise the client sees no displays.
   if (!window_server_->display_manager()->IsReady()) {
     std::unique_ptr<PendingRequest> pending_request(new PendingRequest);
     pending_request->source_info = source_info;
-    pending_request->dm_request.reset(
-        new mojom::DisplayManagerRequest(std::move(request)));
+    pending_request->screen_request =
+        std::make_unique<mojom::ScreenProviderRequest>(std::move(request));
     pending_requests_.push_back(std::move(pending_request));
     return;
   }
diff --git a/services/ui/service.h b/services/ui/service.h
index 2e46cd2..c96180c 100644
--- a/services/ui/service.h
+++ b/services/ui/service.h
@@ -26,10 +26,10 @@
 #include "services/ui/input_devices/input_device_server.h"
 #include "services/ui/public/interfaces/accessibility_manager.mojom.h"
 #include "services/ui/public/interfaces/clipboard.mojom.h"
-#include "services/ui/public/interfaces/display_manager.mojom.h"
 #include "services/ui/public/interfaces/event_injector.mojom.h"
 #include "services/ui/public/interfaces/gpu.mojom.h"
 #include "services/ui/public/interfaces/ime/ime.mojom.h"
+#include "services/ui/public/interfaces/screen_provider.mojom.h"
 #include "services/ui/public/interfaces/user_activity_monitor.mojom.h"
 #include "services/ui/public/interfaces/video_detector.mojom.h"
 #include "services/ui/public/interfaces/window_manager_window_tree_factory.mojom.h"
@@ -138,8 +138,8 @@
   void BindClipboardRequest(mojom::ClipboardRequest request,
                             const service_manager::BindSourceInfo& source_info);
 
-  void BindDisplayManagerRequest(
-      mojom::DisplayManagerRequest request,
+  void BindScreenProviderRequest(
+      mojom::ScreenProviderRequest request,
       const service_manager::BindSourceInfo& source_info);
 
   void BindGpuRequest(mojom::GpuRequest request);
diff --git a/services/ui/ws/test_utils.cc b/services/ui/ws/test_utils.cc
index 8c27263..e94c47e 100644
--- a/services/ui/ws/test_utils.cc
+++ b/services/ui/ws/test_utils.cc
@@ -672,23 +672,23 @@
 
 // ----------------------------------------------------------------------------
 
-TestDisplayManagerObserver::TestDisplayManagerObserver() : binding_(this) {}
+TestScreenProviderObserver::TestScreenProviderObserver() : binding_(this) {}
 
-TestDisplayManagerObserver::~TestDisplayManagerObserver() = default;
+TestScreenProviderObserver::~TestScreenProviderObserver() = default;
 
-mojom::DisplayManagerObserverPtr TestDisplayManagerObserver::GetPtr() {
-  mojom::DisplayManagerObserverPtr ptr;
+mojom::ScreenProviderObserverPtr TestScreenProviderObserver::GetPtr() {
+  mojom::ScreenProviderObserverPtr ptr;
   binding_.Bind(mojo::MakeRequest(&ptr));
   return ptr;
 }
 
-std::string TestDisplayManagerObserver::GetAndClearObserverCalls() {
+std::string TestScreenProviderObserver::GetAndClearObserverCalls() {
   std::string result;
   std::swap(observer_calls_, result);
   return result;
 }
 
-std::string TestDisplayManagerObserver::DisplayIdsToString(
+std::string TestScreenProviderObserver::DisplayIdsToString(
     const std::vector<mojom::WsDisplayPtr>& wm_displays) {
   std::string display_ids;
   for (const auto& wm_display : wm_displays) {
@@ -699,7 +699,7 @@
   return display_ids;
 }
 
-void TestDisplayManagerObserver::OnDisplaysChanged(
+void TestScreenProviderObserver::OnDisplaysChanged(
     std::vector<mojom::WsDisplayPtr> displays,
     int64_t primary_display_id,
     int64_t internal_display_id) {
diff --git a/services/ui/ws/test_utils.h b/services/ui/ws/test_utils.h
index 3057916..3d95a94 100644
--- a/services/ui/ws/test_utils.h
+++ b/services/ui/ws/test_utils.h
@@ -19,7 +19,7 @@
 #include "services/service_manager/public/cpp/bind_source_info.h"
 #include "services/ui/display/screen_manager.h"
 #include "services/ui/display/viewport_metrics.h"
-#include "services/ui/public/interfaces/display_manager.mojom.h"
+#include "services/ui/public/interfaces/screen_provider.mojom.h"
 #include "services/ui/public/interfaces/window_tree.mojom.h"
 #include "services/ui/ws/display.h"
 #include "services/ui/ws/display_binding.h"
@@ -751,12 +751,12 @@
 
 // -----------------------------------------------------------------------------
 
-class TestDisplayManagerObserver : public mojom::DisplayManagerObserver {
+class TestScreenProviderObserver : public mojom::ScreenProviderObserver {
  public:
-  TestDisplayManagerObserver();
-  ~TestDisplayManagerObserver() override;
+  TestScreenProviderObserver();
+  ~TestScreenProviderObserver() override;
 
-  mojom::DisplayManagerObserverPtr GetPtr();
+  mojom::ScreenProviderObserverPtr GetPtr();
 
   std::string GetAndClearObserverCalls();
 
@@ -764,15 +764,15 @@
   std::string DisplayIdsToString(
       const std::vector<mojom::WsDisplayPtr>& wm_displays);
 
-  // mojom::DisplayManagerObserver:
+  // mojom::ScreenProviderObserver:
   void OnDisplaysChanged(std::vector<mojom::WsDisplayPtr> displays,
                          int64_t primary_display_id,
                          int64_t internal_display_id) override;
 
-  mojo::Binding<mojom::DisplayManagerObserver> binding_;
+  mojo::Binding<mojom::ScreenProviderObserver> binding_;
   std::string observer_calls_;
 
-  DISALLOW_COPY_AND_ASSIGN(TestDisplayManagerObserver);
+  DISALLOW_COPY_AND_ASSIGN(TestScreenProviderObserver);
 };
 
 // -----------------------------------------------------------------------------
diff --git a/services/ui/ws/user_display_manager.cc b/services/ui/ws/user_display_manager.cc
index a5e30a3..1fb692d 100644
--- a/services/ui/ws/user_display_manager.cc
+++ b/services/ui/ws/user_display_manager.cc
@@ -27,10 +27,9 @@
 }
 
 void UserDisplayManager::CallOnDisplaysChanged() {
-  display_manager_observers_.ForAllPtrs(
-      [this](mojom::DisplayManagerObserver* observer) {
-        CallOnDisplaysChanged(observer);
-      });
+  observers_.ForAllPtrs([this](mojom::ScreenProviderObserver* observer) {
+    CallOnDisplaysChanged(observer);
+  });
 }
 
 void UserDisplayManager::OnFrameDecorationValuesChanged() {
@@ -39,8 +38,8 @@
 }
 
 void UserDisplayManager::AddDisplayManagerBinding(
-    mojo::InterfaceRequest<mojom::DisplayManager> request) {
-  display_manager_bindings_.AddBinding(this, std::move(request));
+    mojo::InterfaceRequest<mojom::ScreenProvider> request) {
+  bindings_.AddBinding(this, std::move(request));
 }
 
 void UserDisplayManager::OnDisplayUpdated(const display::Display& display) {
@@ -56,14 +55,14 @@
 }
 
 void UserDisplayManager::AddObserver(
-    mojom::DisplayManagerObserverPtr observer) {
-  mojom::DisplayManagerObserver* observer_impl = observer.get();
-  display_manager_observers_.AddPtr(std::move(observer));
+    mojom::ScreenProviderObserverPtr observer) {
+  mojom::ScreenProviderObserver* observer_impl = observer.get();
+  observers_.AddPtr(std::move(observer));
   OnObserverAdded(observer_impl);
 }
 
 void UserDisplayManager::OnObserverAdded(
-    mojom::DisplayManagerObserver* observer) {
+    mojom::ScreenProviderObserver* observer) {
   // Many clients key off the frame decorations to size widgets. Wait for frame
   // decorations before notifying so that we don't have to worry about clients
   // resizing appropriately.
@@ -109,7 +108,7 @@
 }
 
 void UserDisplayManager::CallOnDisplaysChanged(
-    mojom::DisplayManagerObserver* observer) {
+    mojom::ScreenProviderObserver* observer) {
   observer->OnDisplaysChanged(GetAllDisplays(),
                               display::ScreenManager::GetInstance()
                                   ->GetScreen()
diff --git a/services/ui/ws/user_display_manager.h b/services/ui/ws/user_display_manager.h
index 71dab7c..e0205466 100644
--- a/services/ui/ws/user_display_manager.h
+++ b/services/ui/ws/user_display_manager.h
@@ -10,7 +10,7 @@
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/interface_ptr_set.h"
-#include "services/ui/public/interfaces/display_manager.mojom.h"
+#include "services/ui/public/interfaces/screen_provider.mojom.h"
 
 namespace display {
 class Display;
@@ -23,7 +23,7 @@
 
 // Provides per user display state.
 // TODO(sky): merge this with ui::ws::DisplayManager (and rename).
-class UserDisplayManager : public mojom::DisplayManager {
+class UserDisplayManager : public mojom::ScreenProvider {
  public:
   UserDisplayManager(UserDisplayManagerDelegate* delegate);
   ~UserDisplayManager() override;
@@ -37,7 +37,7 @@
   void OnFrameDecorationValuesChanged();
 
   void AddDisplayManagerBinding(
-      mojo::InterfaceRequest<mojom::DisplayManager> request);
+      mojo::InterfaceRequest<mojom::ScreenProvider> request);
 
   // Called when something about the display (e.g. pixel-ratio, size) changes.
   void OnDisplayUpdated(const display::Display& display);
@@ -48,13 +48,13 @@
   // Called when the primary display changes.
   void OnPrimaryDisplayChanged(int64_t primary_display_id);
 
-  // Overriden from mojom::DisplayManager:
-  void AddObserver(mojom::DisplayManagerObserverPtr observer) override;
+  // mojom::ScreenProvider:
+  void AddObserver(mojom::ScreenProviderObserverPtr observer) override;
 
  private:
   // Called when a new observer is added. If frame decorations are available
   // notifies the observer immediately.
-  void OnObserverAdded(mojom::DisplayManagerObserver* observer);
+  void OnObserverAdded(mojom::ScreenProviderObserver* observer);
 
   // Fills in a WsDisplayPtr for |display|.
   mojom::WsDisplayPtr ToWsDisplayPtr(const display::Display& display);
@@ -67,18 +67,17 @@
   void CallOnDisplaysChangedIfNecessary();
 
   // Calls OnDisplaysChanged() on |observer|.
-  void CallOnDisplaysChanged(mojom::DisplayManagerObserver* observer);
+  void CallOnDisplaysChanged(mojom::ScreenProviderObserver* observer);
 
   UserDisplayManagerDelegate* delegate_;
 
   // Set to true the first time at least one Display has valid frame values.
   bool got_valid_frame_decorations_;
 
-  mojo::BindingSet<mojom::DisplayManager> display_manager_bindings_;
+  mojo::BindingSet<mojom::ScreenProvider> bindings_;
 
   // WARNING: only use these once |got_valid_frame_decorations_| is true.
-  mojo::InterfacePtrSet<mojom::DisplayManagerObserver>
-      display_manager_observers_;
+  mojo::InterfacePtrSet<mojom::ScreenProviderObserver> observers_;
 
   // If true DisplayManagerObservers are notified any time there is a display
   // change. If false, observers are only notified when CallOnDisplaysChanged()
diff --git a/services/ui/ws/user_display_manager_unittest.cc b/services/ui/ws/user_display_manager_unittest.cc
index a29eb49..b57f11dd 100644
--- a/services/ui/ws/user_display_manager_unittest.cc
+++ b/services/ui/ws/user_display_manager_unittest.cc
@@ -68,17 +68,17 @@
 TEST_F(UserDisplayManagerTest, OnlyNotifyWhenFrameDecorationsSet) {
   screen_manager().AddDisplay();
 
-  TestDisplayManagerObserver display_manager_observer;
+  TestScreenProviderObserver screen_provider_observer;
   DisplayManager* display_manager = window_server()->display_manager();
   AddWindowManager(window_server());
   UserDisplayManager* user_display_manager =
       display_manager->GetUserDisplayManager();
   ASSERT_TRUE(user_display_manager);
-  user_display_manager->AddObserver(display_manager_observer.GetPtr());
+  user_display_manager->AddObserver(screen_provider_observer.GetPtr());
   RunUntilIdle();
 
   // Observer should not have been notified yet.
-  EXPECT_EQ(std::string(), display_manager_observer.GetAndClearObserverCalls());
+  EXPECT_EQ(std::string(), screen_provider_observer.GetAndClearObserverCalls());
 
   // Set the frame decoration values, which should trigger sending immediately.
   ASSERT_EQ(1u, display_manager->displays().size());
@@ -87,13 +87,13 @@
   RunUntilIdle();
 
   EXPECT_EQ("OnDisplaysChanged 1 -1",
-            display_manager_observer.GetAndClearObserverCalls());
+            screen_provider_observer.GetAndClearObserverCalls());
 }
 
 TEST_F(UserDisplayManagerTest, AddObserverAfterFrameDecorationsSet) {
   screen_manager().AddDisplay();
 
-  TestDisplayManagerObserver display_manager_observer1;
+  TestScreenProviderObserver screen_provider_observer;
   DisplayManager* display_manager = window_server()->display_manager();
   AddWindowManager(window_server());
   UserDisplayManager* user_display_manager =
@@ -103,17 +103,17 @@
   window_server()->GetWindowManagerState()->SetFrameDecorationValues(
       CreateDefaultFrameDecorationValues());
 
-  user_display_manager->AddObserver(display_manager_observer1.GetPtr());
+  user_display_manager->AddObserver(screen_provider_observer.GetPtr());
   RunUntilIdle();
 
   EXPECT_EQ("OnDisplaysChanged 1 -1",
-            display_manager_observer1.GetAndClearObserverCalls());
+            screen_provider_observer.GetAndClearObserverCalls());
 }
 
 TEST_F(UserDisplayManagerTest, AddRemoveDisplay) {
   screen_manager().AddDisplay();
 
-  TestDisplayManagerObserver display_manager_observer1;
+  TestScreenProviderObserver screen_provider_observer;
   DisplayManager* display_manager = window_server()->display_manager();
   AddWindowManager(window_server());
   UserDisplayManager* user_display_manager =
@@ -122,11 +122,11 @@
   ASSERT_EQ(1u, display_manager->displays().size());
   window_server()->GetWindowManagerState()->SetFrameDecorationValues(
       CreateDefaultFrameDecorationValues());
-  user_display_manager->AddObserver(display_manager_observer1.GetPtr());
+  user_display_manager->AddObserver(screen_provider_observer.GetPtr());
   RunUntilIdle();
 
   EXPECT_EQ("OnDisplaysChanged 1 -1",
-            display_manager_observer1.GetAndClearObserverCalls());
+            screen_provider_observer.GetAndClearObserverCalls());
 
   // Add another display.
   const int64_t second_display_id = screen_manager().AddDisplay();
@@ -134,14 +134,14 @@
 
   // Observer should be notified immediately as frame decorations were set.
   EXPECT_EQ("OnDisplaysChanged 1 2 -1",
-            display_manager_observer1.GetAndClearObserverCalls());
+            screen_provider_observer.GetAndClearObserverCalls());
 
   // Remove the display and verify observer is notified.
   screen_manager().RemoveDisplay(second_display_id);
   RunUntilIdle();
 
   EXPECT_EQ("OnDisplaysChanged 1 -1",
-            display_manager_observer1.GetAndClearObserverCalls());
+            screen_provider_observer.GetAndClearObserverCalls());
 }
 
 }  // namespace test
diff --git a/services/ui/ws/window_manager_state.h b/services/ui/ws/window_manager_state.h
index bc8511f..b012826 100644
--- a/services/ui/ws/window_manager_state.h
+++ b/services/ui/ws/window_manager_state.h
@@ -14,7 +14,7 @@
 #include "base/containers/flat_map.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
-#include "services/ui/public/interfaces/display_manager.mojom.h"
+#include "services/ui/public/interfaces/screen_provider.mojom.h"
 #include "services/ui/ws/cursor_state.h"
 #include "services/ui/ws/cursor_state_delegate.h"
 #include "services/ui/ws/event_dispatcher_delegate.h"
diff --git a/services/ui/ws/window_tree_unittest.cc b/services/ui/ws/window_tree_unittest.cc
index 70a923f..dd270be 100644
--- a/services/ui/ws/window_tree_unittest.cc
+++ b/services/ui/ws/window_tree_unittest.cc
@@ -1851,19 +1851,19 @@
   const bool automatically_create_display_roots = false;
   AddWindowManager(window_server(), automatically_create_display_roots);
 
-  TestDisplayManagerObserver display_manager_observer;
+  TestScreenProviderObserver screen_provider_observer;
   DisplayManager* display_manager = window_server()->display_manager();
   UserDisplayManager* user_display_manager =
       display_manager->GetUserDisplayManager();
   ASSERT_TRUE(user_display_manager);
-  user_display_manager->AddObserver(display_manager_observer.GetPtr());
+  user_display_manager->AddObserver(screen_provider_observer.GetPtr());
 
   // Observer should not have been notified yet.
   //
   // NOTE: the RunUntilIdle() calls are necessary anytime the calls are checked
   // as the observer is called via mojo, which is async.
   RunUntilIdle();
-  EXPECT_TRUE(display_manager_observer.GetAndClearObserverCalls().empty());
+  EXPECT_TRUE(screen_provider_observer.GetAndClearObserverCalls().empty());
 
   // Set frame decorations, again observer should not be notified.
   WindowManagerState* window_manager_state =
@@ -1873,7 +1873,7 @@
   window_manager_state->SetFrameDecorationValues(
       mojom::FrameDecorationValues::New());
   RunUntilIdle();
-  EXPECT_TRUE(display_manager_observer.GetAndClearObserverCalls().empty());
+  EXPECT_TRUE(screen_provider_observer.GetAndClearObserverCalls().empty());
 
   // Create a window for the windowmanager and set it as the root.
   ClientWindowId display_root_id = BuildClientWindowId(window_manager_tree, 10);
@@ -1883,7 +1883,7 @@
       window_manager_tree->GetWindowByClientId(display_root_id);
   ASSERT_TRUE(display_root);
   RunUntilIdle();
-  EXPECT_TRUE(display_manager_observer.GetAndClearObserverCalls().empty());
+  EXPECT_TRUE(screen_provider_observer.GetAndClearObserverCalls().empty());
 
   // Add a new display.
   // The value for the scale factor doesn't matter, just choosing something
@@ -1902,7 +1902,7 @@
                   .ProcessSetDisplayRoot(display1, metrics1, is_primary_display,
                                          display_root_id));
   RunUntilIdle();
-  EXPECT_TRUE(display_manager_observer.GetAndClearObserverCalls().empty());
+  EXPECT_TRUE(screen_provider_observer.GetAndClearObserverCalls().empty());
 
   // Configure the displays, updating the bounds of the first display.
   std::vector<display::Display> displays;
@@ -1918,7 +1918,7 @@
   RunUntilIdle();
   EXPECT_EQ("OnDisplaysChanged " + std::to_string(display_id1) + " " +
                 std::to_string(display::kInvalidDisplayId),
-            display_manager_observer.GetAndClearObserverCalls());
+            screen_provider_observer.GetAndClearObserverCalls());
   PlatformDisplay* platform_display1 =
       display_manager->GetDisplayById(display_id1)->platform_display();
   ASSERT_TRUE(platform_display1);
@@ -1938,7 +1938,7 @@
       window_manager_tree->GetWindowByClientId(display_root_id);
   ASSERT_TRUE(display_root2);
   RunUntilIdle();
-  EXPECT_TRUE(display_manager_observer.GetAndClearObserverCalls().empty());
+  EXPECT_TRUE(screen_provider_observer.GetAndClearObserverCalls().empty());
 
   // Add another display.
   const float kDisplay2ScaleFactor = 1.75;
@@ -1954,7 +1954,7 @@
       WindowTreeTestApi(window_manager_tree)
           .ProcessSetDisplayRoot(display2, metrics2, false, display_root_id2));
   RunUntilIdle();
-  EXPECT_TRUE(display_manager_observer.GetAndClearObserverCalls().empty());
+  EXPECT_TRUE(screen_provider_observer.GetAndClearObserverCalls().empty());
 
   // Make |display2| the default, and resize both displays.
   display1.set_bounds(gfx::Rect(0, 0, 1024, 1280));
@@ -1974,7 +1974,7 @@
   RunUntilIdle();
   EXPECT_EQ("OnDisplaysChanged " + std::to_string(display_id1) + " " +
                 std::to_string(display_id2) + " " + std::to_string(display_id2),
-            display_manager_observer.GetAndClearObserverCalls());
+            screen_provider_observer.GetAndClearObserverCalls());
   EXPECT_EQ(
       kDisplay1ScaleFactor * ui::mojom::kCursorMultiplierForExternalDisplays,
       static_cast<TestPlatformDisplay*>(platform_display1)->cursor_scale());
@@ -1988,7 +1988,7 @@
   // Delete the second display, no notification should be sent.
   EXPECT_TRUE(window_manager_tree->DeleteWindow(display_root_id2));
   RunUntilIdle();
-  EXPECT_TRUE(display_manager_observer.GetAndClearObserverCalls().empty());
+  EXPECT_TRUE(screen_provider_observer.GetAndClearObserverCalls().empty());
   EXPECT_FALSE(display_manager->GetDisplayById(display_id2));
 
   // Set the config back to only the first.
@@ -2002,7 +2002,7 @@
   RunUntilIdle();
   EXPECT_EQ("OnDisplaysChanged " + std::to_string(display_id1) + " " +
                 std::to_string(display_id1),
-            display_manager_observer.GetAndClearObserverCalls());
+            screen_provider_observer.GetAndClearObserverCalls());
 
   // The display list should not have display2.
   display::DisplayList& display_list =
diff --git a/services/ui/ws2/BUILD.gn b/services/ui/ws2/BUILD.gn
index 3225c1f..af4d58e 100644
--- a/services/ui/ws2/BUILD.gn
+++ b/services/ui/ws2/BUILD.gn
@@ -29,8 +29,8 @@
     "client_root.h",
     "client_window.cc",
     "client_window.h",
-    "display_manager_mus.cc",
-    "display_manager_mus.h",
+    "screen_provider.cc",
+    "screen_provider.h",
     "window_host_frame_sink_client.cc",
     "window_host_frame_sink_client.h",
     "window_service.cc",
@@ -106,7 +106,7 @@
   testonly = true
 
   sources = [
-    "display_manager_mus_unittest.cc",
+    "screen_provider_unittest.cc",
     "window_service_client_unittest.cc",
     "window_tree_client_unittest.cc",
   ]
diff --git a/services/ui/ws2/display_manager_mus.h b/services/ui/ws2/display_manager_mus.h
deleted file mode 100644
index 35b44d0e..0000000
--- a/services/ui/ws2/display_manager_mus.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2018 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 SERVICES_UI_WS2_DISPLAY_MANAGER_MUS_H_
-#define SERVICES_UI_WS2_DISPLAY_MANAGER_MUS_H_
-
-#include "base/component_export.h"
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
-#include "services/ui/public/interfaces/display_manager.mojom.h"
-#include "ui/display/display_observer.h"
-
-namespace ui {
-namespace ws2 {
-
-// Provides information about displays to window service clients.
-// display::Screen must outlive this object. Exported for test.
-// TODO(jamescook): Rename to DisplayManagerWs or whatever we end up calling the
-// window server library. It is named Mus to match ScreenMus.
-class COMPONENT_EXPORT(WINDOW_SERVICE) DisplayManagerMus
-    : public mojom::DisplayManager,
-      public display::DisplayObserver {
- public:
-  DisplayManagerMus();
-  ~DisplayManagerMus() override;
-
-  void AddBinding(mojom::DisplayManagerRequest request);
-
-  // mojom::DisplayManager:
-  void AddObserver(mojom::DisplayManagerObserverPtr observer) override;
-
-  // display::DisplayObserver:
-  void OnDidProcessDisplayChanges() override;
-
- private:
-  std::vector<mojom::WsDisplayPtr> GetAllDisplays();
-
-  void NotifyAllObservers();
-
-  void NotifyObserver(mojom::DisplayManagerObserver* observer);
-
-  mojo::BindingSet<mojom::DisplayManager> bindings_;
-
-  mojo::InterfacePtrSet<mojom::DisplayManagerObserver> observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(DisplayManagerMus);
-};
-
-}  // namespace ws2
-}  // namespace ui
-
-#endif  // SERVICES_UI_WS2_DISPLAY_MANAGER_MUS_H_
diff --git a/services/ui/ws2/display_manager_mus.cc b/services/ui/ws2/screen_provider.cc
similarity index 71%
rename from services/ui/ws2/display_manager_mus.cc
rename to services/ui/ws2/screen_provider.cc
index 0471c47..65776ec 100644
--- a/services/ui/ws2/display_manager_mus.cc
+++ b/services/ui/ws2/screen_provider.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "services/ui/ws2/display_manager_mus.h"
+#include "services/ui/ws2/screen_provider.h"
 
 #include "ui/display/screen.h"
 
@@ -24,43 +24,42 @@
 
 }  // namespace
 
-DisplayManagerMus::DisplayManagerMus() {
+ScreenProvider::ScreenProvider() {
   Screen::GetScreen()->AddObserver(this);
 }
 
-DisplayManagerMus::~DisplayManagerMus() {
+ScreenProvider::~ScreenProvider() {
   Screen::GetScreen()->RemoveObserver(this);
 }
 
-void DisplayManagerMus::AddBinding(mojom::DisplayManagerRequest request) {
+void ScreenProvider::AddBinding(mojom::ScreenProviderRequest request) {
   bindings_.AddBinding(this, std::move(request));
 }
 
-void DisplayManagerMus::AddObserver(mojom::DisplayManagerObserverPtr observer) {
-  mojom::DisplayManagerObserver* observer_impl = observer.get();
+void ScreenProvider::AddObserver(mojom::ScreenProviderObserverPtr observer) {
+  mojom::ScreenProviderObserver* observer_impl = observer.get();
   observers_.AddPtr(std::move(observer));
   NotifyObserver(observer_impl);
 }
 
-void DisplayManagerMus::OnDidProcessDisplayChanges() {
+void ScreenProvider::OnDidProcessDisplayChanges() {
   // Display changes happen in batches, so notify observers after the batch is
   // complete, rather than on every add/remove/metrics change.
   NotifyAllObservers();
 }
 
-void DisplayManagerMus::NotifyAllObservers() {
-  observers_.ForAllPtrs([this](mojom::DisplayManagerObserver* observer) {
+void ScreenProvider::NotifyAllObservers() {
+  observers_.ForAllPtrs([this](mojom::ScreenProviderObserver* observer) {
     NotifyObserver(observer);
   });
 }
 
-void DisplayManagerMus::NotifyObserver(
-    mojom::DisplayManagerObserver* observer) {
+void ScreenProvider::NotifyObserver(mojom::ScreenProviderObserver* observer) {
   observer->OnDisplaysChanged(GetAllDisplays(), GetPrimaryDisplayId(),
                               GetInternalDisplayId());
 }
 
-std::vector<mojom::WsDisplayPtr> DisplayManagerMus::GetAllDisplays() {
+std::vector<mojom::WsDisplayPtr> ScreenProvider::GetAllDisplays() {
   std::vector<Display> displays = Screen::GetScreen()->GetAllDisplays();
 
   std::vector<mojom::WsDisplayPtr> ws_displays;
diff --git a/services/ui/ws2/screen_provider.h b/services/ui/ws2/screen_provider.h
new file mode 100644
index 0000000..e38c68e1
--- /dev/null
+++ b/services/ui/ws2/screen_provider.h
@@ -0,0 +1,52 @@
+// Copyright 2018 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 SERVICES_UI_WS2_SCREEN_PROVIDER_H_
+#define SERVICES_UI_WS2_SCREEN_PROVIDER_H_
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "services/ui/public/interfaces/screen_provider.mojom.h"
+#include "ui/display/display_observer.h"
+
+namespace ui {
+namespace ws2 {
+
+// Provides information about displays to window service clients.
+// display::Screen must outlive this object. Exported for test.
+class COMPONENT_EXPORT(WINDOW_SERVICE) ScreenProvider
+    : public mojom::ScreenProvider,
+      public display::DisplayObserver {
+ public:
+  ScreenProvider();
+  ~ScreenProvider() override;
+
+  void AddBinding(mojom::ScreenProviderRequest request);
+
+  // mojom::ScreenProvider:
+  void AddObserver(mojom::ScreenProviderObserverPtr observer) override;
+
+  // display::DisplayObserver:
+  void OnDidProcessDisplayChanges() override;
+
+ private:
+  std::vector<mojom::WsDisplayPtr> GetAllDisplays();
+
+  void NotifyAllObservers();
+
+  void NotifyObserver(mojom::ScreenProviderObserver* observer);
+
+  mojo::BindingSet<mojom::ScreenProvider> bindings_;
+
+  mojo::InterfacePtrSet<mojom::ScreenProviderObserver> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScreenProvider);
+};
+
+}  // namespace ws2
+}  // namespace ui
+
+#endif  // SERVICES_UI_WS2_SCREEN_PROVIDER_H_
diff --git a/services/ui/ws2/display_manager_mus_unittest.cc b/services/ui/ws2/screen_provider_unittest.cc
similarity index 84%
rename from services/ui/ws2/display_manager_mus_unittest.cc
rename to services/ui/ws2/screen_provider_unittest.cc
index 82e455c..01a6897 100644
--- a/services/ui/ws2/display_manager_mus_unittest.cc
+++ b/services/ui/ws2/screen_provider_unittest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "services/ui/ws2/display_manager_mus.h"
+#include "services/ui/ws2/screen_provider.h"
 
 #include <stdint.h>
 
 #include "base/strings/string_number_conversions.h"
 #include "services/ui/common/task_runner_test_base.h"
-#include "services/ui/public/interfaces/display_manager.mojom.h"
+#include "services/ui/public/interfaces/screen_provider.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/display/display.h"
 #include "ui/display/screen_base.h"
@@ -62,18 +62,18 @@
   DISALLOW_COPY_AND_ASSIGN(TestScreen);
 };
 
-class TestDisplayManagerObserver : public mojom::DisplayManagerObserver {
+class TestScreenProviderObserver : public mojom::ScreenProviderObserver {
  public:
-  TestDisplayManagerObserver() = default;
-  ~TestDisplayManagerObserver() override = default;
+  TestScreenProviderObserver() = default;
+  ~TestScreenProviderObserver() override = default;
 
-  mojom::DisplayManagerObserverPtr GetPtr() {
-    mojom::DisplayManagerObserverPtr ptr;
+  mojom::ScreenProviderObserverPtr GetPtr() {
+    mojom::ScreenProviderObserverPtr ptr;
     binding_.Bind(mojo::MakeRequest(&ptr));
     return ptr;
   }
 
-  // mojom::DisplayManagerObserver:
+  // mojom::ScreenProviderObserver:
   void OnDisplaysChanged(std::vector<mojom::WsDisplayPtr> displays,
                          int64_t primary_display_id,
                          int64_t internal_display_id) override {
@@ -82,29 +82,29 @@
     internal_display_id_ = internal_display_id;
   }
 
-  mojo::Binding<mojom::DisplayManagerObserver> binding_{this};
+  mojo::Binding<mojom::ScreenProviderObserver> binding_{this};
   std::string display_ids_;
   int64_t primary_display_id_ = 0;
   int64_t internal_display_id_ = 0;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(TestDisplayManagerObserver);
+  DISALLOW_COPY_AND_ASSIGN(TestScreenProviderObserver);
 };
 
 // Mojo needs a task runner.
-using DisplayManagerMusTest = TaskRunnerTestBase;
+using ScreenProviderTest = TaskRunnerTestBase;
 
-TEST_F(DisplayManagerMusTest, AddRemoveDisplay) {
+TEST_F(ScreenProviderTest, AddRemoveDisplay) {
   TestScreen screen;
   screen.AddDisplay(Display(111, gfx::Rect(0, 0, 640, 480)),
                     DisplayList::Type::PRIMARY);
   Display::SetInternalDisplayId(111);
 
-  DisplayManagerMus manager;
-  TestDisplayManagerObserver observer;
+  ScreenProvider screen_provider;
+  TestScreenProviderObserver observer;
 
   // Adding an observer triggers an update.
-  manager.AddObserver(observer.GetPtr());
+  screen_provider.AddObserver(observer.GetPtr());
   // Wait for mojo message to observer.
   RunUntilIdle();
   EXPECT_EQ("111", observer.display_ids_);
diff --git a/services/ui/ws2/window_service.cc b/services/ui/ws2/window_service.cc
index 412ca0e..bc6727b 100644
--- a/services/ui/ws2/window_service.cc
+++ b/services/ui/ws2/window_service.cc
@@ -7,8 +7,8 @@
 #include "base/bind.h"
 #include "base/single_thread_task_runner.h"
 #include "services/ui/ws2/client_window.h"
-#include "services/ui/ws2/display_manager_mus.h"
 #include "services/ui/ws2/gpu_support.h"
+#include "services/ui/ws2/screen_provider.h"
 #include "services/ui/ws2/window_service_client.h"
 #include "services/ui/ws2/window_service_delegate.h"
 #include "services/ui/ws2/window_tree_factory.h"
@@ -21,7 +21,7 @@
                              std::unique_ptr<GpuSupport> gpu_support)
     : delegate_(delegate),
       gpu_support_(std::move(gpu_support)),
-      display_manager_mus_(std::make_unique<DisplayManagerMus>()) {
+      screen_provider_(std::make_unique<ScreenProvider>()) {
   // MouseLocationManager is necessary for providing the shared memory with the
   // location of the mouse to clients.
   aura::Env::GetInstance()->CreateMouseLocationManager();
@@ -56,7 +56,7 @@
   registry_.AddInterface(base::BindRepeating(
       &WindowService::BindClipboardRequest, base::Unretained(this)));
   registry_.AddInterface(base::BindRepeating(
-      &WindowService::BindDisplayManagerRequest, base::Unretained(this)));
+      &WindowService::BindScreenProviderRequest, base::Unretained(this)));
   registry_.AddInterface(base::BindRepeating(
       &WindowService::BindImeDriverRequest, base::Unretained(this)));
   registry_.AddInterface(base::BindRepeating(
@@ -88,9 +88,9 @@
   NOTIMPLEMENTED();
 }
 
-void WindowService::BindDisplayManagerRequest(
-    mojom::DisplayManagerRequest request) {
-  display_manager_mus_->AddBinding(std::move(request));
+void WindowService::BindScreenProviderRequest(
+    mojom::ScreenProviderRequest request) {
+  screen_provider_->AddBinding(std::move(request));
 }
 
 void WindowService::BindImeDriverRequest(mojom::IMEDriverRequest request) {
diff --git a/services/ui/ws2/window_service.h b/services/ui/ws2/window_service.h
index 060c990..94e35e4 100644
--- a/services/ui/ws2/window_service.h
+++ b/services/ui/ws2/window_service.h
@@ -12,8 +12,8 @@
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/ui/public/interfaces/clipboard.mojom.h"
-#include "services/ui/public/interfaces/display_manager.mojom.h"
 #include "services/ui/public/interfaces/ime/ime.mojom.h"
+#include "services/ui/public/interfaces/screen_provider.mojom.h"
 #include "services/ui/public/interfaces/window_tree.mojom.h"
 #include "services/ui/ws2/ids.h"
 #include "ui/aura/mus/property_converter.h"
@@ -31,8 +31,8 @@
 namespace ws2 {
 
 class ClientWindow;
-class DisplayManagerMus;
 class GpuSupport;
+class ScreenProvider;
 class WindowServiceClient;
 class WindowServiceDelegate;
 class WindowTreeFactory;
@@ -70,7 +70,7 @@
 
  private:
   void BindClipboardRequest(mojom::ClipboardRequest request);
-  void BindDisplayManagerRequest(mojom::DisplayManagerRequest request);
+  void BindScreenProviderRequest(mojom::ScreenProviderRequest request);
   void BindImeDriverRequest(mojom::IMEDriverRequest request);
   void BindWindowTreeFactoryRequest(
       ui::mojom::WindowTreeFactoryRequest request);
@@ -80,7 +80,7 @@
   // GpuSupport may be null in tests.
   std::unique_ptr<GpuSupport> gpu_support_;
 
-  std::unique_ptr<DisplayManagerMus> display_manager_mus_;
+  std::unique_ptr<ScreenProvider> screen_provider_;
 
   service_manager::BinderRegistry registry_;
 
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 276ac70..085b7fd 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -203,6 +203,18 @@
 #define SK_SUPPORT_LEGACY_TILED_BITMAPS
 #endif
 
+// The matrix image filter imperceptibly alters the following two layout tests:
+//   fast/css/transformed-mask.html
+//   fast/reflections/opacity-reflection-transform.html
+// and changes the following cc_unittests:
+//   LayerTreeHostCommonTest.VisibleRectWithScalingClippingAndFilters
+//   LayerTreeHostCommonTest.VisibleRectWithClippingAndFilters
+// Landing the fix in Skia behind this flag will allow those all to be updated
+// together in Chrome (along with the removal of this flag).
+#ifndef SK_IGNORE_MATRIX_IMAGE_FILTER_FIX
+#define SK_IGNORE_MATRIX_IMAGE_FILTER_FIX
+#endif
+
 // remove after rebaselining svg layout tests
 #ifndef SK_SUPPORT_LEGACY_SVG_ARC_TO
 #define SK_SUPPORT_LEGACY_SVG_ARC_TO
diff --git a/testing/buildbot/chromium.goma.json b/testing/buildbot/chromium.goma.json
index 59524459..d4ac99c 100644
--- a/testing/buildbot/chromium.goma.json
+++ b/testing/buildbot/chromium.goma.json
@@ -39,6 +39,63 @@
       }
     ]
   },
+  "Chromium Linux Goma RBE Staging (clobber)": {
+    "additional_compile_targets": [
+      "all"
+    ],
+    "gtest_tests": [
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      }
+    ]
+  },
+  "Chromium Linux Goma RBE Staging (dbg)": {
+    "additional_compile_targets": [
+      "all"
+    ],
+    "gtest_tests": [
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      }
+    ]
+  },
+  "Chromium Linux Goma RBE Staging (dbg) (clobber)": {
+    "additional_compile_targets": [
+      "all"
+    ],
+    "gtest_tests": [
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      }
+    ]
+  },
   "Chromium Linux Goma Staging": {
     "additional_compile_targets": [
       "all"
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index 70930a2..91b717e 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -198,13 +198,7 @@
 # Finish ServiceWorker networking glue rewrite.
 # http://crbug.com/715640
 -ServiceWorkerTestWithJSBindings/ServiceWorkerTest.MimeHandlerView/0
--ServiceWorkerTestWithJSBindings/ServiceWorkerTest.SWServedBackgroundPageReceivesEvent/0
--ServiceWorkerTestWithJSBindings/ServiceWorkerTest.WebAccessibleResourcesFetch/0
--ServiceWorkerTestWithJSBindings/ServiceWorkerTest.WebAccessibleResourcesIframeSrc/0
 -ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.MimeHandlerView/0
--ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.SWServedBackgroundPageReceivesEvent/0
--ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.WebAccessibleResourcesFetch/0
--ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.WebAccessibleResourcesIframeSrc/0
 
 # Support URLLoaderFactories from embedder in shared workers.
 # https://crbug.com/839982
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 125a0434..34e3722e 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -845,6 +845,14 @@
           'gtest_tests': 'goma_gtests',
         },
       },
+      'Chromium Linux Goma RBE Staging (clobber)': {
+        'additional_compile_targets': [
+          'all',
+        ],
+        'test_suites': {
+          'gtest_tests': 'goma_gtests',
+        },
+      },
       'Chromium Linux Goma RBE Staging': {
         'additional_compile_targets': [
           'all',
@@ -853,6 +861,22 @@
           'gtest_tests': 'goma_gtests',
         },
       },
+      'Chromium Linux Goma RBE Staging (dbg) (clobber)': {
+        'additional_compile_targets': [
+          'all',
+        ],
+        'test_suites': {
+          'gtest_tests': 'goma_gtests',
+        },
+      },
+      'Chromium Linux Goma RBE Staging (dbg)': {
+        'additional_compile_targets': [
+          'all',
+        ],
+        'test_suites': {
+          'gtest_tests': 'goma_gtests',
+        },
+      },
       'Chromium Linux Goma Staging': {
         'additional_compile_targets': [
           'all',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 18efee6..33c5706 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2218,6 +2218,21 @@
             ]
         }
     ],
+    "OfflinePagesDinoPageExperiment": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "OfflinePagesShowAlternateDinoPage"
+                    ]
+                }
+            ]
+        }
+    ],
     "OfflinePagesPrefetchingSuggestions": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index e4996bd..48eb47a 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -117,7 +117,7 @@
 crbug.com/591099 animations/animation-ready-reject-script-forbidden.html [ Timeout ]
 crbug.com/591099 animations/cross-fade-list-style-image.html [ Failure ]
 crbug.com/591099 animations/interpolation/backdrop-filter-interpolation.html [ Timeout ]
-crbug.com/591099 animations/interpolation/line-height-interpolation.html [ Pass Timeout ]
+crbug.com/591099 animations/interpolation/line-height-interpolation.html [ Timeout ]
 crbug.com/591099 animations/interpolation/svg-stroke-dasharray-interpolation.html [ Timeout ]
 crbug.com/591099 animations/interpolation/webkit-clip-path-interpolation.html [ Pass Timeout ]
 crbug.com/591099 animations/rotate-transform-equivalent.html [ Failure ]
@@ -167,7 +167,6 @@
 crbug.com/591099 css3/flexbox/flexbox-with-multi-column-property.html [ Failure ]
 crbug.com/591099 css3/flexbox/intrinsic-width-orthogonal-writing-mode.html [ Failure ]
 crbug.com/591099 css3/flexbox/line-wrapping.html [ Failure ]
-crbug.com/714962 css3/flexbox/mozilla/flexbox-items-as-stacking-contexts-2.html [ Failure ]
 crbug.com/591099 css3/flexbox/position-absolute-child-with-contenteditable.html [ Failure ]
 crbug.com/591099 css3/flexbox/scrollbars-auto.html [ Failure ]
 crbug.com/591099 css3/flexbox/scrollbars.html [ Failure ]
@@ -246,27 +245,21 @@
 crbug.com/714962 external/wpt/WebCryptoAPI/import_export/test_rsa_importKey.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/acid/acid3/numbered-tests.html [ Crash ]
 crbug.com/591099 external/wpt/acid/acid3/test.html [ Crash ]
-crbug.com/591099 external/wpt/content-security-policy/reporting/report-original-url.sub.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/credential-management/federatedcredential-framed-get.sub.https.html [ Pass ]
 crbug.com/591099 external/wpt/credential-management/passwordcredential-framed-get.sub.https.html [ Pass ]
 crbug.com/635619 external/wpt/css/CSS2/floats/floats-in-table-caption-001.html [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/floats/floats-rule3-outside-right-002.xht [ Pass ]
-crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-bfc-006.xht [ Pass ]
 crbug.com/714962 external/wpt/css/CSS2/linebox/vertical-align-baseline-005a.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-empty-001.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-insert-001e.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-insert-001h.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-insert-002e.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-nested-002.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-remove-006.xht [ Pass ]
 crbug.com/635619 external/wpt/css/CSS2/normal-flow/margin-collapsing-in-table-caption-002.html [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/normal-flow/min-width-applies-to-005.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/root-box-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/text/white-space-mixed-003.xht [ Pass ]
 crbug.com/714962 external/wpt/css/css-backgrounds/background-attachment-local/attachment-local-clipping-color-5.html [ Failure ]
 crbug.com/714962 external/wpt/css/css-backgrounds/background-attachment-local/attachment-local-clipping-image-5.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-backgrounds/box-shadow-syntax-001.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-contain/contain-size-breaks-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-display/display-contents-details.html [ Crash ]
 crbug.com/591099 external/wpt/css/css-display/display-contents-dynamic-list-001-inline.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-display/display-contents-dynamic-list-001-none.html [ Failure ]
@@ -274,23 +267,14 @@
 crbug.com/591099 external/wpt/css/css-display/display-contents-list-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-filter/filtered-block-is-container.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-filter/filtered-inline-is-container.html [ Crash ]
-crbug.com/591099 external/wpt/css/css-flexbox/flex-minimum-width-flex-items-006.xht [ Pass ]
-crbug.com/591099 external/wpt/css/css-flexbox/flexbox_justifycontent-center-overflow.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-flexbox/percentage-heights-001.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-flexbox/percentage-heights-003.html [ Pass ]
 crbug.com/714962 external/wpt/css/css-fonts/font-features-across-space-1.html [ Pass ]
 crbug.com/714962 external/wpt/css/css-fonts/font-features-across-space-3.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-fonts/font-synthesis-03.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-fonts/font-variant-alternates-02.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-fonts/font-variant-alternates-04.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-fonts/font-variant-alternates-parsing.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-fonts/font-variant-descriptor-01.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-fonts/font-variant-ligatures-11.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-fonts/matching/fixed-stretch-style-over-weight.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-fonts/matching/stretch-distance-over-weight-distance.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-fonts/matching/style-ranges-over-weight-direction.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-fonts/test_font_family_parsing.html [ Timeout ]
-crbug.com/591099 external/wpt/css/css-fonts/variations/font-shorthand.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-009.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-010.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-011.html [ Failure ]
@@ -300,15 +284,6 @@
 crbug.com/591099 external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-010.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-011.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-012.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-layout-api/fallback-layout-invalid-fragment-request.https.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/css/css-layout-api/layout-child-fixed.https.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/css/css-layout-api/layout-child-inlines.https.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/css/css-layout-api/perform-child-layout-fixed-inline-size-vrl.https.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/css/css-layout-api/style-map-multi.https.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/css/css-paint-api/geometry-background-image-001.https.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/css/css-paint-api/paint2d-composite.https.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/css/css-paint-api/parse-input-arguments-002.https.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/css/css-paint-api/parse-input-arguments-013.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/css/css-position/position-sticky-writing-modes.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-rhythm/ [ Skip ]
 crbug.com/591099 external/wpt/css/css-scroll-anchoring/clipped-scrollers-skipped.html [ Failure ]
@@ -321,10 +296,10 @@
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-006.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-007.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-008.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-008.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-002.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-003.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-003.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-radial-gradient-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-radial-gradient-002.html [ Failure ]
@@ -343,16 +318,15 @@
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-012.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-013.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-014.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-015.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-015.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-016.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-017.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-017.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-018.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-019.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-020.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-020.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-021.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-022.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-023.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-024.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-025.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/circle/shape-outside-circle-013.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/circle/shape-outside-circle-014.html [ Failure ]
@@ -376,7 +350,7 @@
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-014.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-015.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-016.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-017.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-017.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-018.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-019.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-020.html [ Failure ]
@@ -385,7 +359,7 @@
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-023.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-024.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-025.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-030.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-030.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-031.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/inset/shape-outside-inset-010.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/inset/shape-outside-inset-011.html [ Failure ]
@@ -400,7 +374,7 @@
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-009.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-010.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-011.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-012.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-012.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-013.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-014.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-015.html [ Failure ]
@@ -428,12 +402,10 @@
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-017.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-018.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-019.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-sizing/intrinsic-percent-non-replaced-001.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-sizing/intrinsic-percent-non-replaced-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-sizing/intrinsic-percent-non-replaced-003.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-tables/fixup-dynamic-anonymous-table-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-tables/height-distribution/percentage-sizing-of-table-cell-children.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-tables/table-model-fixup-2.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-tables/table-model-fixup.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-tables/width-distribution/td-with-subpixel-padding-vertical-rl.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-color-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-above-left-001.xht [ Failure ]
@@ -468,28 +440,12 @@
 crbug.com/591099 external/wpt/css/css-text/white-space/seg-break-transformation-011.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-text/white-space/seg-break-transformation-012.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-text/word-break/word-break-break-all-004.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-transforms/2d-rotate-js.html [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-transforms/transform-abspos-006.html [ Failure ]
 crbug.com/714962 external/wpt/css/css-transforms/transform-abspos-007.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-transforms/transform-generated-002.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-transforms/transform-transformed-tr-percent-height-child.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-transforms/transform3d-perspective-008.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-transitions/transition-property-002.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-transitions/transitioncancel-001.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-typed-om/stylevalue-subclasses/numeric-objects/numeric-factory.tentative.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/background-position.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/fill-opacity.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/grid-gap.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/margin.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/speak.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/stroke.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/transform-box.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-ui/outline-015.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-ui/text-overflow-010.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-ui/text-overflow-015.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-values/calc-serialization.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-variables/variable-definition.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-variables/variable-presentation-attribute.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-ui/text-overflow-015.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-icb-vlr-003.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-icb-vlr-005.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-icb-vlr-011.xht [ Pass ]
@@ -544,35 +500,30 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-076.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-088.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-104.xht [ Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-108.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-108.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-112.xht [ Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-116.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-124.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-116.xht [ Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-124.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-128.xht [ Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-132.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-136.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-140.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-144.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-148.xht [ Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-156.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-156.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-160.xht [ Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-164.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-172.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-176.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-188.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-192.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-204.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-208.xht [ Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-212.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-220.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-220.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-224.xht [ Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-228.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-002.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-010.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-011.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-012.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/available-size-015.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-017.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-018.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/baseline-inline-non-replaced-004.xht [ Failure ]
@@ -581,20 +532,18 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/clearance-calculations-vrl-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/clearance-calculations-vrl-004.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/clearance-calculations-vrl-006.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/clip-rect-vlr-009.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-004.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-006.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-008.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-008.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-vlr-013.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-004.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-006.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-010.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-012.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/inline-block-alignment-006.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/inline-block-alignment-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/line-box-direction-vrl-009.xht [ Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/line-box-height-vlr-021.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/margin-collapse-vrl-010.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/mongolian-orientation-002.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/ortho-htb-alongside-vrl-floats-002.xht [ Failure ]
@@ -624,7 +573,7 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vrl-012.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vrl-019.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vrl-020.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vrl-021.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vrl-021.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vrl-023.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vrl-024.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-003.xht [ Failure ]
@@ -649,17 +598,11 @@
 crbug.com/591099 external/wpt/css/cssom/interfaces.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/css/geometry/interfaces.worker.html [ Pass ]
 crbug.com/591099 external/wpt/css/selectors/focus-within-004.html [ Pass ]
-crbug.com/591099 external/wpt/css/selectors/user-invalid.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/dependent-builtin.html [ Pass ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/descriptor-fallback.html [ Pass ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/descriptor-prefix.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-content-vert-001a.xhtml [ Failure ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-break-request-horiz-001a.html [ Pass ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-multi-item-vert-001b.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-003v.html [ Pass ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-006v.html [ Pass ]
-crbug.com/714962 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-items-as-stacking-contexts-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-011.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-012.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-014.html [ Failure ]
@@ -668,16 +611,13 @@
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/ib-split/split-inner-inline-2.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-break-inside-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-007.html [ Failure ]
-crbug.com/591099 external/wpt/dom/events/Event-defaultPrevented.html [ Failure Pass ]
-crbug.com/591099 external/wpt/dom/historical.html [ Failure Pass ]
-crbug.com/591099 external/wpt/dom/nodes/Document-createEvent.html [ Failure Pass ]
 crbug.com/591099 external/wpt/dom/nodes/Element-classlist.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/nodes/Element-matches.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/nodes/Element-webkitMatchesSelector.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/nodes/Node-compareDocumentPosition.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/nodes/Node-contains.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/nodes/ParentNode-querySelector-All-xht.xht [ Timeout ]
-crbug.com/591099 external/wpt/dom/nodes/ParentNode-querySelector-All.html [ Failure Timeout ]
+crbug.com/591099 external/wpt/dom/nodes/ParentNode-querySelector-All.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/ranges/Range-compareBoundaryPoints.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/ranges/Range-comparePoint.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/ranges/Range-insertNode.html [ Timeout ]
@@ -686,8 +626,7 @@
 crbug.com/591099 external/wpt/dom/ranges/Range-mutations-dataChange.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/ranges/Range-set.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/ranges/Range-surroundContents.html [ Timeout ]
-crbug.com/591099 external/wpt/domxpath/002.html [ Failure Pass ]
-crbug.com/591099 external/wpt/domxpath/xml_xpath_runner.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/domxpath/xml_xpath_runner.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/backcolor.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/editing/run/bold.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/fontname.html [ Timeout ]
@@ -696,7 +635,7 @@
 crbug.com/591099 external/wpt/editing/run/formatblock.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/forwarddelete.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/hilitecolor.html [ Timeout ]
-crbug.com/591099 external/wpt/editing/run/indent.html [ Failure Timeout ]
+crbug.com/591099 external/wpt/editing/run/indent.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/editing/run/inserthorizontalrule.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/inserthtml.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/insertlinebreak.html [ Timeout ]
@@ -809,25 +748,12 @@
 crbug.com/591099 external/wpt/encoding/legacy-mb-tchinese/big5/big5-encode-href-errors-misc.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/legacy-mb-tchinese/big5/big5-encode-href.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/textdecoder-fatal-single-byte.html [ Timeout ]
-crbug.com/591099 external/wpt/fetch/api/abort/general.any.sharedworker.html [ Failure Pass Timeout ]
-crbug.com/591099 external/wpt/fetch/api/policies/csp-blocked-worker.html [ Failure Pass ]
-crbug.com/591099 external/wpt/fetch/api/response/response-clone.html [ Failure Pass ]
-crbug.com/591099 external/wpt/fetch/api/response/response-error.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/fullscreen/api/document-fullscreen-enabled-cross-origin.sub.html [ Failure Pass ]
 crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure ]
-crbug.com/591099 external/wpt/hr-time/timing-attack.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/html-media-capture/capture_audio_cancel-manual.html [ Failure ]
 crbug.com/591099 external/wpt/html-media-capture/capture_image_cancel-manual.html [ Failure ]
 crbug.com/591099 external/wpt/html-media-capture/capture_video_cancel-manual.html [ Failure ]
-crbug.com/591099 external/wpt/html/browsers/browsing-the-web/history-traversal/hashchange_event.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/browsers/browsing-the-web/history-traversal/same-url.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/html/browsers/the-window-object/accessing-other-browsing-contexts/indexed-browsing-contexts-03.html [ Failure Pass Timeout ]
-crbug.com/591099 external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/close_unload.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/html/browsers/windows/noreferrer-window-name.html [ Timeout ]
 crbug.com/591099 external/wpt/html/dom/documents/dom-tree-accessors/Document.currentScript.html [ Pass ]
-crbug.com/591099 external/wpt/html/dom/dynamic-markup-insertion/opening-the-input-stream/001.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/dom/dynamic-markup-insertion/opening-the-input-stream/008.html [ Failure Pass Timeout ]
 crbug.com/591099 external/wpt/html/dom/interfaces.https.html [ Timeout ]
 crbug.com/591099 external/wpt/html/editing/editing-0/autocapitalization/autocapitalize.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/utf-16be.html [ Timeout ]
@@ -837,48 +763,28 @@
 crbug.com/591099 external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/windows-1252.html [ Timeout ]
 crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/flow-content-0/dialog.html [ Failure ]
 crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-fieldset-element-0/legend-block-formatting-context.html [ Failure ]
-crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/width.html [ Pass ]
-crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2k.html [ Pass ]
 crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-auto.html [ Failure ]
 crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-percentage.html [ Failure ]
 crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-inline-sizing/svg-inline.html [ Timeout ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-non-snap-to-lines.html [ Failure ]
-crbug.com/591099 external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/semantics/embedded-content/the-video-element/video_initially_paused.html [ Pass ]
-crbug.com/591099 external/wpt/html/semantics/forms/the-form-element/form-autocomplete.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/semantics/forms/the-input-element/time.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-menu.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-skip-no-boxes.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/interactive-elements/the-dialog-element/abspos-dialog-layout.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/interactive-elements/the-dialog-element/centering.html [ Crash ]
-crbug.com/591099 external/wpt/html/semantics/scripting-1/the-script-element/script-type-and-language-empty.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html/syntax/parsing/named-character-references.html [ Timeout ]
 crbug.com/591099 external/wpt/html/the-xhtml-syntax/parsing-xhtml-documents/xhtml-mathml-dtd-entity-1.htm [ Pass Timeout ]
 crbug.com/591099 external/wpt/html/the-xhtml-syntax/parsing-xhtml-documents/xhtml-mathml-dtd-entity-4.htm [ Pass Timeout ]
 crbug.com/591099 external/wpt/html/the-xhtml-syntax/parsing-xhtml-documents/xhtml-mathml-dtd-entity-7.htm [ Pass Timeout ]
 crbug.com/591099 external/wpt/longtask-timing/longtask-in-sibling-iframe.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/media-source/URL-createObjectURL-revoke.html [ Failure Pass ]
 crbug.com/591099 external/wpt/media-source/mediasource-getvideoplaybackquality.html [ Timeout ]
 crbug.com/591099 external/wpt/mimesniff/mime-types/parsing.any.html [ Timeout ]
 crbug.com/591099 external/wpt/mimesniff/mime-types/parsing.any.worker.html [ Timeout ]
-crbug.com/591099 external/wpt/navigation-timing/nav2_test_instance_accessors.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/notifications/event-onerror-denied-manual.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/offscreen-canvas/compositing/2d.composite.uncovered.image.destination-in.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.nowrap.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/offscreen-canvas/drawing-rectangles-to-the-canvas/2d.fillRect.zero.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.pattern.basic.nocontext.worker.html [ Crash ]
-crbug.com/591099 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.pattern.repeat.nullsuffix.worker.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/offscreen-canvas/path-objects/2d.path.stroke.prune.closed.html [ Failure Pass ]
-crbug.com/591099 external/wpt/offscreen-canvas/the-offscreen-canvas/2d.getcontext.extraargs.html [ Failure Pass ]
 crbug.com/591099 external/wpt/offscreen-canvas/the-offscreen-canvas/offscreencanvas.getcontext.worker.html [ Pass ]
-crbug.com/591099 external/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.parse.percent.html [ Failure Pass ]
-crbug.com/591099 external/wpt/orientation-event/idlharness.html [ Failure Pass ]
 crbug.com/591099 external/wpt/payment-request/payment-allowed-by-feature-policy.https.sub.html [ Pass ]
 crbug.com/591099 external/wpt/payment-request/payment-disabled-by-feature-policy.https.sub.html [ Pass ]
-crbug.com/591099 external/wpt/performance-timeline/po-observe.any.worker.html [ Failure Pass ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_attributes_hoverable_pointers-manual.html [ Timeout ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_click_during_capture-manual.html [ Crash Timeout ]
-crbug.com/591099 external/wpt/pointerevents/pointerevent_on_event_handlers.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_pointerleave_pen-manual.html [ Failure ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-span-test_touch-manual.html [ Failure ]
 crbug.com/591099 external/wpt/quirks/line-height-calculation.html [ Failure ]
@@ -906,68 +812,38 @@
 crbug.com/591099 external/wpt/selection/extend-20.html [ Timeout ]
 crbug.com/591099 external/wpt/selection/selectAllChildren.html [ Timeout ]
 crbug.com/591099 external/wpt/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html [ Failure ]
-crbug.com/591099 external/wpt/shadow-dom/ShadowRoot-interface.html [ Failure Pass ]
-crbug.com/591099 external/wpt/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-010.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-011.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/streams/piping/error-propagation-forward.html [ Failure Pass ]
-crbug.com/591099 external/wpt/streams/piping/pipe-through.dedicatedworker.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/streams/readable-streams/general.dedicatedworker.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/streams/writable-streams/bad-strategies.sharedworker.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/svg/interfaces.html [ Timeout ]
 crbug.com/591099 external/wpt/svg/linking/reftests/href-filter-element.html [ Failure ]
 crbug.com/591099 external/wpt/url/url-setters.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/vibration/silent-ignore.html [ Failure Pass ]
 crbug.com/591099 external/wpt/wasm/wasm_local_iframe_test.html [ Failure ]
 crbug.com/591099 external/wpt/web-animations/animation-model/animation-types/interpolation-per-property.html [ Timeout ]
-crbug.com/591099 external/wpt/web-animations/interfaces/Animation/constructor.html [ Failure Pass ]
-crbug.com/591099 external/wpt/web-animations/timing-model/animation-effects/phases-and-states.html [ Failure Pass ]
-crbug.com/591099 external/wpt/web-animations/timing-model/animations/reversing-an-animation.html [ Failure Pass ]
-crbug.com/591099 external/wpt/web-share/share-securecontext.http.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/webaudio/idlharness.https.html [ Timeout ]
-crbug.com/591099 external/wpt/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-onended.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/webmessaging/broadcastchannel/sandbox.html [ Failure ]
-crbug.com/591099 external/wpt/webrtc/RTCPeerConnection-addTransceiver.html [ Failure Pass ]
-crbug.com/591099 external/wpt/webrtc/RTCRtpParameters-headerExtensions.html [ Failure Pass Timeout ]
 crbug.com/591099 external/wpt/webrtc/interfaces.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/webrtc/protocol/video-codecs.html [ Failure ]
-crbug.com/591099 external/wpt/websockets/interfaces/WebSocket/close/close-nested.html [ Failure Pass ]
 crbug.com/591099 external/wpt/webstorage/storage_setitem.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/webvr/idlharness.https.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_completely_move_up.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_partially_move_up.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/bidi/bidi_ruby.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/bidi/u002E_u2029_u05D0.html [ Pass ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/dom_override_cue_line.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/evil/9_cues_overlapping_completely.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/evil/9_cues_overlapping_completely_all_cues_have_same_timestamp.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/line_percent_and_integer_mixed_overlap_move_up.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/font_properties.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/font_shorthand.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_font_properties.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_white-space_normal_wrapped.html [ Pass ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_color.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_font_properties.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_white-space_normal_wrapped.html [ Pass ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_with_class.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/font_properties.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/font_shorthand.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_font_properties.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/not_root_selector.html [ Pass ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/type_selector_root.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_font_properties.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_timestamp_future.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_font_properties.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/default_styles/bold_object_default_font-style.html [ Pass ]
 crbug.com/591099 external/wpt/workers/Worker_terminate_event_queue.htm [ Timeout ]
-crbug.com/591099 external/wpt/workers/semantics/multiple-workers/004.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/xhr/abort-after-send.htm [ Failure Pass ]
 crbug.com/591099 external/wpt/xhr/send-authentication-prompt-2-manual.htm [ Failure ]
-crbug.com/591099 external/wpt/xhr/setrequestheader-content-type.htm [ Failure Pass ]
 crbug.com/591099 fast/backgrounds/background-clip-text.html [ Failure ]
 crbug.com/591099 fast/backgrounds/background-leakage-transforms.html [ Failure ]
 crbug.com/591099 fast/backgrounds/border-radius-split-background-image.html [ Failure ]
@@ -1001,7 +877,6 @@
 crbug.com/591099 fast/block/positioning/abspos-auto-left-and-width-change-parent-margin-left.html [ Crash ]
 crbug.com/591099 fast/block/positioning/child-of-fixed-pos-after-movement.html [ Crash ]
 crbug.com/591099 fast/block/positioning/complex-positioned-movement-inline-ancestor.html [ Failure ]
-crbug.com/591099 fast/block/positioning/differing-writing-modes-replaced.html [ Failure ]
 crbug.com/591099 fast/block/positioning/fixed-in-abs-height-change.html [ Crash ]
 crbug.com/591099 fast/block/positioning/positioned-child-inside-relative-positioned-anonymous-block.html [ Failure ]
 crbug.com/591099 fast/block/positioning/relative-overflow-replaced.html [ Failure ]
@@ -1166,7 +1041,7 @@
 crbug.com/714962 fast/events/event-on-culled_inline.html [ Failure ]
 crbug.com/591099 fast/events/keyboardevent-getModifierState.html [ Timeout ]
 crbug.com/714962 fast/events/middleClickAutoscroll-latching.html [ Pass Timeout ]
-crbug.com/714962 fast/events/mouse-down-on-pseudo-element-remove-crash.html [ Failure Pass ]
+crbug.com/714962 fast/events/mouse-down-on-pseudo-element-remove-crash.html [ Failure ]
 crbug.com/591099 fast/events/mouse-relative-position.html [ Failure ]
 crbug.com/591099 fast/events/mouseevent-getModifierState.html [ Timeout ]
 crbug.com/591099 fast/events/onclick-list-marker.html [ Failure ]
@@ -1603,16 +1478,16 @@
 crbug.com/591099 http/tests/csspaint/invalidation-border-image.html [ Timeout ]
 crbug.com/591099 http/tests/csspaint/invalidation-content-image.html [ Timeout ]
 crbug.com/591099 http/tests/devtools/console/console-functions.js [ Pass Timeout ]
-crbug.com/591099 http/tests/devtools/console/console-preserve-scroll.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/console/console-preserve-scroll.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/console/console-search.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/console/console-viewport-control.js [ Failure ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-1.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-2.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-2.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-enter-behaviour.js [ Pass Timeout ]
 crbug.com/714962 http/tests/devtools/editor/text-editor-formatter.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/editor/text-editor-line-breaks.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/editor/text-editor-reveal-line.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/editor/text-editor-search-switch-editor.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/editor/text-editor-line-breaks.js [ Pass Timeout ]
+crbug.com/591099 http/tests/devtools/editor/text-editor-reveal-line.js [ Pass Timeout ]
+crbug.com/591099 http/tests/devtools/editor/text-editor-search-switch-editor.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-word-jumps.js [ Pass ]
 crbug.com/714962 http/tests/devtools/elements/edit/edit-dom-actions-4.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/elements-inspect-iframe-from-different-domain.js [ Timeout ]
@@ -1620,33 +1495,34 @@
 crbug.com/591099 http/tests/devtools/elements/highlight/highlight-css-shapes-outside-scroll.js [ Failure ]
 crbug.com/591099 http/tests/devtools/elements/highlight/highlight-css-shapes-outside.js [ Failure ]
 crbug.com/714962 http/tests/devtools/elements/inspect-pseudo-element.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/elements/styles-1/add-new-rule-with-style-after-body.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/elements/styles-1/commit-selector-mark-matching.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/elements/styles-1/add-new-rule-with-style-after-body.js [ Pass Timeout ]
+crbug.com/591099 http/tests/devtools/elements/styles-1/commit-selector-mark-matching.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/elements/styles-2/paste-property.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/elements/styles-3/styles-add-blank-property.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/elements/styles-3/styles-add-new-rule-colon.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/elements/styles-3/styles-add-new-rule-colon.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/elements/styles-3/styles-add-new-rule-tab.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/elements/styles-3/styles-add-new-rule.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/elements/styles-3/styles-change-node-while-editing.js [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/elements/styles-3/styles-commit-editing.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/elements/styles-3/styles-commit-editing.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/elements/styles-3/styles-disable-inherited.js [ Failure ]
-crbug.com/591099 http/tests/devtools/elements/styles-4/styles-do-not-detach-sourcemap-on-edits.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/elements/styles-4/styles-formatting.js [ Pass Timeout ]
-crbug.com/591099 http/tests/devtools/elements/styles-4/styles-live-locations-leak.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/elements/styles-4/styles-do-not-detach-sourcemap-on-edits.js [ Pass Timeout ]
+crbug.com/591099 http/tests/devtools/elements/styles-4/styles-formatting.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/elements/styles-4/styles-live-locations-leak.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/elements/styles-4/styles-update-from-js.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/elements/styles-4/undo-add-new-rule.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/elements/styles-4/undo-add-property.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/elements/styles/stylesheet-tracking.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/elements/styles-4/undo-add-new-rule.js [ Pass Timeout ]
+crbug.com/591099 http/tests/devtools/elements/styles-4/undo-add-property.js [ Pass Timeout ]
+crbug.com/591099 http/tests/devtools/elements/styles/stylesheet-tracking.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/extensions/extensions-sidebar.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/network/network-datareceived.js [ Failure ]
 crbug.com/591099 http/tests/devtools/persistence/persistence-merge-editor-tabs.js [ Failure ]
-crbug.com/591099 http/tests/devtools/search/source-frame-replace-2.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/search/source-frame-replace-4.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/sources/debugger-breakpoints/dom-breakpoints.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/search/source-frame-replace-2.js [ Pass Timeout ]
+crbug.com/591099 http/tests/devtools/search/source-frame-replace-4.js [ Pass Timeout ]
+crbug.com/591099 http/tests/devtools/sources/debugger-breakpoints/dom-breakpoints.js [ Pass Timeout ]
+crbug.com/591099 http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/sources/debugger-frameworks/frameworks-skip-step-in.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/sources/debugger-ui/debugger-inline-values.js [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/sources/debugger/debugger-proto-property.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/sources/debugger/debugger-proto-property.js [ Pass Timeout ]
+crbug.com/591099 http/tests/devtools/sources/debugger/source-frame-breakpoint-decorations.js [ Failure ]
 crbug.com/591099 http/tests/devtools/text-autosizing-override.js [ Failure ]
 crbug.com/591099 http/tests/devtools/tracing/scroll-invalidations.js [ Failure ]
 crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-bound-function.js [ Failure ]
@@ -1656,7 +1532,7 @@
 crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.js [ Failure ]
 crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.js [ Failure ]
 crbug.com/591099 http/tests/images/restyle-decode-error.html [ Failure ]
-crbug.com/783102 http/tests/incremental/frame-focus-before-load.html [ Timeout ]
+crbug.com/783102 http/tests/incremental/frame-focus-before-load.html [ Pass Timeout ]
 crbug.com/591099 http/tests/incremental/slow-utf8-text.pl [ Pass Timeout ]
 crbug.com/591099 http/tests/loading/nested_bad_objects.php [ Failure ]
 crbug.com/591099 http/tests/loading/preload-picture-nested.html [ Failure ]
@@ -1986,7 +1862,7 @@
 crbug.com/591099 svg/parser/whitespace-length-invalid-1.html [ Pass Timeout ]
 crbug.com/591099 svg/parser/whitespace-length-invalid-2.html [ Pass Timeout ]
 crbug.com/591099 svg/parser/whitespace-length-invalid-3.html [ Pass Timeout ]
-crbug.com/591099 svg/parser/whitespace-length-invalid-4.html [ Pass Timeout ]
+crbug.com/591099 svg/parser/whitespace-length-invalid-4.html [ Timeout ]
 crbug.com/591099 svg/parser/whitespace-number.html [ Timeout ]
 crbug.com/591099 svg/text/foreignObject-text-clipping-bug.xml [ Failure ]
 crbug.com/714962 svg/text/tspan-multiple-outline.svg [ Failure ]
@@ -2076,7 +1952,7 @@
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/mouse-relative-position.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/mouseevent-getModifierState.html [ Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/onclick-list-marker.html [ Failure ]
-crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-capture-transition-events.html [ Timeout ]
+crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-capture-transition-events.html [ Pass Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/touch-capture.html [ Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/select-element.html [ Failure Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/sequential-focus-navigation-starting-point.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index f429f07..6f8dc3d7 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2788,6 +2788,14 @@
 crbug.com/832071 virtual/navigation-mojo-response/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-016.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-013.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-011.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-014.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-012.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-015.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-010.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-009.html [ Failure ]
 crbug.com/626703 external/wpt/console/console-countReset-logging-manual.html [ Skip ]
 crbug.com/626703 [ Mac10.12 ] external/wpt/accelerometer/Accelerometer.https.html [ Timeout ]
 crbug.com/626703 [ Retina ] external/wpt/pointerevents/pointerevent_touch-action-button-test_touch-manual.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index 338c800..40469be 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -350,11 +350,6 @@
              "--disable-smooth-scrolling"]
   },
   {
-    "prefix": "mojo-notifications",
-    "base": "http/tests/notifications",
-    "args": ["--enable-blink-features=NotificationsWithMojo"]
-  },
-  {
     "prefix": "scalefactor150",
     "base": "fast/events/synthetic-events",
     "args": ["--force-device-scale-factor=1.5"]
@@ -663,6 +658,16 @@
     "args": ["--enable-features=SignedHTTPExchange,NetworkService"]
   },
   {
+    "prefix": "htxg-origin-trial",
+    "base": "http/tests/loading/htxg",
+    "args": ["--enable-features=SignedHTTPExchangeOriginTrial"]
+  },
+  {
+    "prefix": "htxg-origin-trial-with-network-service",
+    "base": "http/tests/loading/htxg",
+    "args": ["--enable-features=SignedHTTPExchangeOriginTrial,NetworkService"]
+  },
+  {
     "prefix": "picture-in-picture",
     "base": "external/wpt/picture-in-picture",
     "args": ["--enable-features=PictureInPicture,UseSurfaceLayerForVideo"]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index f917993..1dfd2edd 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -49705,6 +49705,102 @@
      {}
     ]
    ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-009.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-009.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-010.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-010.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-011.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-011.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-012.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-012.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-013.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-013.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-014.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-014.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-015.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-015.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-016.html": [
+    [
+     "/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-016.html",
+     [
+      [
+       "/css/css-shapes/shape-outside/shape-image/gradients/reference/shape-outside-linear-gradient-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-shapes/shape-outside/shape-image/shape-image-000.html": [
     [
      "/css/css-shapes/shape-outside/shape-image/shape-image-000.html",
@@ -282460,107 +282556,107 @@
    "testharness"
   ],
   "css/css-contain/contain-layout-001.html": [
-   "e40223fa77c569be5465ce55532eca46d9893cad",
+   "937507caf01330e9beafc7a5ba850284d35c4369",
    "reftest"
   ],
   "css/css-contain/contain-layout-002.html": [
-   "30d5b2c379a9af602b9c882067ebe922c25038bb",
+   "f37c06237a09aea4eaa09bdc08d9969f7763f0b7",
    "reftest"
   ],
   "css/css-contain/contain-layout-003.html": [
-   "5e19e8c0f7a9a9f73238ef6e6b28462883740c6e",
+   "b031fdb81e39d3044e133e6e332aff31b2844d8a",
    "reftest"
   ],
   "css/css-contain/contain-layout-004.html": [
-   "391769dc944021336fdf3f3409be7e2be494a685",
+   "dea2a6b1dada9e57f36d2245ac67c05fd9c4ad0b",
    "reftest"
   ],
   "css/css-contain/contain-layout-005.html": [
-   "c64e0379993570d68ebb96c7b6df3f5f0f60674a",
+   "60b834ef7b5becf76f5cacd55b2b9c4774562637",
    "reftest"
   ],
   "css/css-contain/contain-layout-breaks-001.html": [
-   "2904f490dbe202ed821d6d74652ec177ad8eacab",
+   "09fcfd311126800c7ce63f27c3154ef31fc647bd",
    "reftest"
   ],
   "css/css-contain/contain-layout-breaks-002.html": [
-   "947877963e2d57b249950ff75e218b23b19a0ef5",
+   "985252e8226e0cba567b49f44665804e3a12bc40",
    "reftest"
   ],
   "css/css-contain/contain-paint-001.html": [
-   "27fb558b0913d1787e881fa1db42f8e925ef859b",
+   "c26e9cc0daf7cb92b0966656a17fb0c931e86d5f",
    "reftest"
   ],
   "css/css-contain/contain-paint-002.html": [
-   "6c549e4be755d47fa4f0ffcffc62ffdab4edf15a",
+   "50adc0e83ba0d3bffd957dbf8acdf7474f6350f5",
    "reftest"
   ],
   "css/css-contain/contain-paint-003.html": [
-   "f49511f28e8b0f51df677acae3cd9c07b1717657",
+   "7eb703232b2a448b3b49394ed0102b65aa37e647",
    "reftest"
   ],
   "css/css-contain/contain-paint-004.html": [
-   "e39e7be877e3802262f1451067363d9c26b8dd4b",
+   "2db5aaea054ed4b3a2c2db1786f29fc44515cdd4",
    "reftest"
   ],
   "css/css-contain/contain-paint-005.html": [
-   "2c3063121d36648ffe636950f7a36f0d565331aa",
+   "68c7155386ef96ba8fe22ce55d996634f928b703",
    "reftest"
   ],
   "css/css-contain/contain-paint-006.html": [
-   "72b002b39ae9b252678157f1f95ecbcd33261230",
+   "935d160de8000eb1f83ac6a987b6c7047ca80e93",
    "reftest"
   ],
   "css/css-contain/contain-paint-007.html": [
-   "c78854ac437a9cf3433da3c99c9934384a22851d",
+   "3e7d3cd3ccb55b7b8574be24fb2f180a6ce0af36",
    "reftest"
   ],
   "css/css-contain/contain-paint-008.html": [
-   "0bd9de602bc622a1a1a74ac7d4434d66e6efadbe",
+   "5540aaf33b5b841d95f84ead3459f634cf444299",
    "reftest"
   ],
   "css/css-contain/contain-size-001.html": [
-   "04979088ce29652117bc74c6cc34c054b258d153",
+   "089c4fd7352f91a85d5d8f6bf8c5f261c868cd37",
    "reftest"
   ],
   "css/css-contain/contain-size-002.html": [
-   "908f73fa8d56f2eb4bf39862a666875ea21b18db",
+   "ea16d90e56729c1678b327412cd945a0dea6b762",
    "reftest"
   ],
   "css/css-contain/contain-size-003.html": [
-   "8668ef203078d96a051cdf437fa8d089492c4121",
+   "4b1fd16d90f0eebd7ce97a82a5ef55806f92060e",
    "reftest"
   ],
   "css/css-contain/contain-size-004.html": [
-   "767d429b99eaf77227153d74a131864d0078d88a",
+   "94390f137f15d9667b3d5f105d13881fe7d53ea5",
    "reftest"
   ],
   "css/css-contain/contain-size-005.html": [
-   "fe04ae74a7bfb5fd3629651c3d9a6dcdc1084537",
+   "dfb0708ceeda5812a7434454f39a360d576597ea",
    "reftest"
   ],
   "css/css-contain/contain-size-breaks-001.html": [
-   "b936d15fad907793fb5a0249d643097cee2e79ff",
+   "3a3c80029a6c126c584a21e2ff3b25e5459c32e8",
    "reftest"
   ],
   "css/css-contain/contain-style-breaks-001.html": [
-   "9325ee8666d1825644849dee8068d9f1e415917b",
+   "cc6748966bc23c1f8be0aaa57384d0dc1d80c8d1",
    "reftest"
   ],
   "css/css-contain/contain-style-breaks-002.html": [
-   "60ba2d5b65d740365d248055cecaf0dbd5a38044",
+   "e4db568843b89407e787a4ace67602358a11d5d5",
    "reftest"
   ],
   "css/css-contain/contain-style-breaks-003.html": [
-   "9bc7320984a55b349dae3d3f891eb8524c82da26",
+   "fb79c638966ddbc1fd6f265d79569b1461558d08",
    "reftest"
   ],
   "css/css-contain/contain-style-breaks-004.html": [
-   "eb389ef6335039fddf1db70307d4c0886a6a1d06",
+   "8f485b4c176a0fbd46494e678a1b65fee881b799",
    "reftest"
   ],
   "css/css-contain/contain-style-breaks-005.html": [
-   "f88bf147234294dffdbd831de90c20dbe81d0342",
+   "2c57f0016d0e8f43c5a37bd169cd948794c686ea",
    "reftest"
   ],
   "css/css-contain/contain-style-counters-ref.html": [
@@ -282568,35 +282664,35 @@
    "support"
   ],
   "css/css-contain/contain-style-counters.html": [
-   "056b3597f3555c803c74a8f6277a06626efd12ea",
+   "712b04117d388e4e2d6747edde2c955b54d397fd",
    "reftest"
   ],
   "css/css-contain/counter-scoping-001.html": [
-   "aba8dd6e85fc14d928de33903eed919f527ccfaf",
+   "237c7d44e913ef11a77260d6bf890f8da64a7cb6",
    "reftest"
   ],
   "css/css-contain/counter-scoping-002.html": [
-   "cdab600690babdcebe693991bf716f4772eeda4a",
+   "e54d1abf1026d6fd371685ca60d73a791b2ea67e",
    "reftest"
   ],
   "css/css-contain/counter-scoping-003.html": [
-   "220a8cb80dc067593b3eb72e9bee6d03589483e7",
+   "547aeb36f80a406f3c3a5502001e6799f5308142",
    "reftest"
   ],
   "css/css-contain/quote-scoping-001.html": [
-   "33a5755b8e14976806afe451621875c5e150b0de",
+   "8c2594eb25b5c44503fd33311ddeed1ba494bf7e",
    "reftest"
   ],
   "css/css-contain/quote-scoping-002.html": [
-   "0130a683755b8829033d053b7f7bb7d48c04639a",
+   "2bb36460620d89989cbb49bd84d7d9f736a4e5a4",
    "reftest"
   ],
   "css/css-contain/quote-scoping-003.html": [
-   "26e5a5d36ac865c4253da894375a3194f97c7f01",
+   "46aa7fadb81fbf45c379edc7771fb4d1e0858f29",
    "reftest"
   ],
   "css/css-contain/quote-scoping-004.html": [
-   "fb3af3126d0700e58219fe0550bab57661c7b7ad",
+   "5067c9308951cae6deb33f4383398f96d859428f",
    "reftest"
   ],
   "css/css-contain/reference/contain-layout-002-ref.html": [
@@ -299339,6 +299435,38 @@
    "2f2b95904fad670919fae32cb94284118a45566c",
    "reftest"
   ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-009.html": [
+   "2226228acb7badb0145118891235733b62bd5504",
+   "reftest"
+  ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-010.html": [
+   "8bcee868c33ce352ff4435584b01b91a867e2699",
+   "reftest"
+  ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-011.html": [
+   "a8f9bd56d4fe6f508c4251f97ff32b0555c3b8ac",
+   "reftest"
+  ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-012.html": [
+   "f4e6edd54826da5374c63651af925bcb4dc2f7d3",
+   "reftest"
+  ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-013.html": [
+   "764980f1beaedaf608096161525ee1f4326bee18",
+   "reftest"
+  ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-014.html": [
+   "42305d67e0f88ed75bee44edc992c0e92a761597",
+   "reftest"
+  ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-015.html": [
+   "b8294d4201dd68a5c91c6f4da7acb9a352ba0cbc",
+   "reftest"
+  ],
+  "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-016.html": [
+   "18d2fe95bf79efe975a07b332aad3e0fd0e0f298",
+   "reftest"
+  ],
   "css/css-shapes/shape-outside/shape-image/gradients/shape-outside-radial-gradient-001.html": [
    "b13df2df3be12ac74a7933794d91558c416b412c",
    "testharness"
@@ -392960,7 +393088,7 @@
    "support"
   ],
   "worklets/resources/credentials-tests.js": [
-   "642b8039439a20609788d36a0bc7d116fc8e4f6d",
+   "bddea8fd1aeab9ae3c6d6c0c6d3d286299e31b2e",
    "support"
   ],
   "worklets/resources/credentials.py": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-001.html
index ab3328e7..decea3b2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-001.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="paint containment does not apply to non atomic inlines">
   <link rel="match" href="reference/contain-size-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-paint">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
 
 <style>
 span {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-002.html
index 578893d..8bbf951 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-002.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-002.html
@@ -6,7 +6,7 @@
   <meta name=flags content="ahem">
   <meta name=assert content="layout containment does not apply to ruby-base">
   <link rel="match" href="reference/contain-layout-002-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-paint">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
 
 <style>
 rb {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-003.html
index b4d0672..2d59bd8 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-003.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-003.html
@@ -6,7 +6,7 @@
   <meta name=flags content="ahem">
   <meta name=assert content="layout containment does not apply to ruby-base-container">
   <link rel="match" href="reference/contain-layout-002-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-paint">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
 
 <style>
 rbc {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-004.html
index 0287b4a..ef74af9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-004.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-004.html
@@ -6,7 +6,7 @@
   <meta name=flags content="ahem">
   <meta name=assert content="layout containment does not apply to ruby-text-container">
   <link rel="match" href="reference/contain-layout-004-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-paint">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
 
 <style>
 rtc {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-005.html
index 3a6a3da..a12aef53 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-005.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-005.html
@@ -6,7 +6,7 @@
   <meta name=flags content="ahem">
   <meta name=assert content="layout containment does not apply to ruby-text">
   <link rel="match" href="reference/contain-layout-005-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-paint">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
 
 <style>
 rt {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-breaks-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-breaks-001.html
index 3599989..a85cf2c6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-breaks-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-breaks-001.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="layout containment allows forced breaks.">
   <link rel="match" href="reference/contain-style-breaks-004-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-layout">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-layout">
   <link rel=help href="https://drafts.csswg.org/css-break-3/#forced-break">
 
 <style>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-breaks-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-breaks-002.html
index d45b40c..4398387f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-breaks-002.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-breaks-002.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="forced breaks within layout containment do not propagate to the parent.">
   <link rel="match" href="reference/contain-layout-breaks-002-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-layout">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-layout">
   <link rel=help href="https://drafts.csswg.org/css-break-3/#forced-break">
 
 <style>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-001.html
index e0c17c4..37609e6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-001.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="paint containment clips at the padding edge, not content edge, and takes corner clipping into account">
   <link rel="match" href="reference/contain-paint-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-paint">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
 
 <style>
 div {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-002.html
index 6ea64782..ff59a234 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-002.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-002.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="paint containment does not apply to non atomic inlines">
   <link rel="match" href="reference/contain-size-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-paint">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
 
 <style>
 span {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-003.html
index 9ab7270..7db9c20 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-003.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-003.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="paint containment applies to the principal box, which is the table wrapper box for tables">
   <link rel="match" href="reference/contain-size-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-paint">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
 
 <style>
 table { contain: paint; }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-004.html
index 7567c92..a3941b3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-004.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-004.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="paint containment applies to the principal box, which for list items excludes the list marker">
   <link rel="match" href="reference/contain-paint-004-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-paint">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
 
 <style>
 li { contain: paint; }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-005.html
index ce565e1..71ceae4f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-005.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-005.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="paint containment does not apply to ruby-base">
   <link rel="match" href="reference/contain-size-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-paint">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
 
 <style>
 rb {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-006.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-006.html
index 54149fa..1349c186 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-006.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-006.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="paint containment does not apply to ruby-base-container">
   <link rel="match" href="reference/contain-size-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-paint">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
 
 <style>
 rbc {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-007.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-007.html
index fb76def..b02bd53 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-007.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-007.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="paint containment does not apply to ruby-text-container">
   <link rel="match" href="reference/contain-paint-007-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-paint">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
 
 <style>
 rtc {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-008.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-008.html
index 8dd628b..8fd7ca25 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-008.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-008.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="paint containment does not apply to ruby-text">
   <link rel="match" href="reference/contain-paint-008-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-paint">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
 
 <style>
 rt {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-001.html
index f5491a7..5ed871b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-001.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="size containment does not apply to non atomic inlines">
   <link rel="match" href="reference/contain-size-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-size">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-size">
 
 <style>
 div { overflow: hidden; }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-002.html
index fe30aa2..e844c67f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-002.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-002.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="size containment does not to apply ruby-base, which is an internatl ruby element">
   <link rel="match" href="reference/contain-size-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-size">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-size">
   <link rel=help href="https://drafts.csswg.org/css-display-3/#internal-ruby-element">
 
 <style>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-003.html
index 4f3cb9608..95827dc 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-003.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-003.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="size containment does not to apply ruby-base-container, which is an internatl ruby element">
   <link rel="match" href="reference/contain-size-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-size">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-size">
   <link rel=help href="https://drafts.csswg.org/css-display-3/#internal-ruby-element">
 
 <style>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-004.html
index 43691bcc..b043310 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-004.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-004.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="size containment does not to apply ruby-text-container, which is an internatl ruby element">
   <link rel="match" href="reference/contain-size-004-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-size">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-size">
   <link rel=help href="https://drafts.csswg.org/css-display-3/#internal-ruby-element">
 
 <style>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-005.html
index 3687d4a..9e35a85a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-005.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-005.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="size containment does not to apply ruby-text, which is an internatl ruby element">
   <link rel="match" href="reference/contain-size-005-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-size">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-size">
   <link rel=help href="https://drafts.csswg.org/css-display-3/#internal-ruby-element">
 
 <style>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-breaks-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-breaks-001.html
index b3284f5..d8538f6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-breaks-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-breaks-001.html
@@ -6,7 +6,7 @@
   <meta name=flags content="ahem">
   <meta name=assert content="size containment makes element monolithic">
   <link rel="match" href="reference/contain-size-breaks-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-style">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
   <link rel=help href="https://drafts.csswg.org/css-break-3/#monolithic">
 
 <style>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-001.html
index 22ae3a57..9e5c27a0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-001.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="style containment is (no longer) supposed to have any effect on the break-inside property">
   <link rel="match" href="reference/contain-style-breaks-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-style">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
 
 <style>
 article {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-002.html
index eabbf5b..1b089c84 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-002.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-002.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="style containment is not (any longer) supposed to have any effect on the break-inside property. Same as -001, applying containment on the parent.">
   <link rel="match" href="reference/contain-style-breaks-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-style">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
 
 <style>
 article {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-003.html
index 9668c49..2cfd590 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-003.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-003.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="style containment is not (any longer) supposed to have any effect on the break-inside property. Same as -001, applying break-inside on the parent.">
   <link rel="match" href="reference/contain-style-breaks-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-style">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
 
 <style>
 article {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-004.html
index c2998f9..98e79a6db 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-004.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-004.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="style containment is not (any longer) supposed to have any effect on the break-before property.">
   <link rel="match" href="reference/contain-style-breaks-004-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-style">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
 
 <style>
 article {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-005.html
index 89fb829..bfcd1fb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-005.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-breaks-005.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="style containment is not (any longer) supposed to have any effect on the break-after property.">
   <link rel="match" href="reference/contain-style-breaks-004-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-style">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
 
 <style>
 article {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters.html
index 73de6dc..55bf97f9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <title>CSS Containment Test: contain:style for counters</title>
-<link rel="help" href="https://drafts.csswg.org/css-contain/#containment-style">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-style">
 <link rel="match" href="contain-style-counters-ref.html">
 <style>
     #t1 { contain: style }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/counter-scoping-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/counter-scoping-001.html
index 92b075e..f7d40dc5a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/counter-scoping-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/counter-scoping-001.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="counter-increment is scoped to the subtree and creates a new counter at the root of the subtree">
   <link rel="match" href="reference/counter-scoping-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-style">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
 
 <style>
 div {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/counter-scoping-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/counter-scoping-002.html
index 4dde5cdc..0af148cd 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/counter-scoping-002.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/counter-scoping-002.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="counter-set is scoped to the subtree and creates a new counter at the root of the subtree">
   <link rel="match" href="reference/counter-scoping-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-style">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
   <link rel=help href="https://drafts.csswg.org/css-lists-3/#propdef-counter-set">
 
 <style>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/counter-scoping-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/counter-scoping-003.html
index 5d52401..c4a004f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/counter-scoping-003.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/counter-scoping-003.html
@@ -5,7 +5,7 @@
   <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
   <meta name=flags content="">
   <meta name=assert content="When considering the effects of the scoped property on elements inside the subtree, the element at the base of the subtree is treated as if it was the root of the document">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-style">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
   <link rel="match" href="reference/counter-scoping-003-ref.html">
 
 <style>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-001.html
index cc6c4d4..b440fdcd 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-001.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="style containment cause the open-quote value of the content property are scoped to the element's subtree">
   <link rel="match" href="reference/quote-scoping-001-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-style">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
 
 <style>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-002.html
index 6d699dbd..d79ec2d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-002.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-002.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="style containment cause the close-quote value of the content property are scoped to the element's subtree">
   <link rel="match" href="reference/quote-scoping-002-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-style">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
 
 <style>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-003.html
index dceee59..ee0420e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-003.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-003.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="style containment cause the no-open-quote value of the content property are scoped to the element's subtree">
   <link rel="match" href="reference/quote-scoping-003-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-style">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
 
 <style>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-004.html
index 8c75578..b314370 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-004.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/quote-scoping-004.html
@@ -6,7 +6,7 @@
   <meta name=flags content="">
   <meta name=assert content="style containment cause the no-close-quote value of the content property are scoped to the element's subtree">
   <link rel="match" href="reference/quote-scoping-003-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain/#containment-style">
+  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
 
 <style>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-009.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-009.html
new file mode 100644
index 0000000..eb04734
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-009.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: vertical-rl and text-orientation: sideways</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient under vertical-rl and text-orientation: sideways."/>
+    <style type="text/css">
+    .container {
+      writing-mode: vertical-rl;
+      text-orientation: sideways;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the top. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 50%, transparent 50%);
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the bottom. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 50%, transparent 50%);
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-010.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-010.html
new file mode 100644
index 0000000..26335a6b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-010.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: vertical-lr and text-orientation: sideways</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient under vertical-lr and text-orientation: sideways."/>
+    <style type="text/css">
+    .container {
+      writing-mode: vertical-lr;
+      text-orientation: sideways;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the top. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 50%, transparent 50%);
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the bottom. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 50%, transparent 50%);
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-011.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-011.html
new file mode 100644
index 0000000..3daa63c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-011.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: vertical-rl</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient with shape-margin under vertical-rl."/>
+    <style type="text/css">
+    .container {
+      writing-mode: vertical-rl;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the top. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 25%, transparent 25%);
+      shape-margin: 25%;
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the bottom. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 5%, transparent 5%);
+      shape-margin: 45%
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-012.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-012.html
new file mode 100644
index 0000000..52f5e8a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-012.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: vertical-lr</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient with shape-margin under vertical-lr."/>
+    <style type="text/css">
+    .container {
+      writing-mode: vertical-lr;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the top. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 25%, transparent 25%);
+      shape-margin: 25%;
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the bottom. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 5%, transparent 5%);
+      shape-margin: 45%
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-013.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-013.html
new file mode 100644
index 0000000..66a2850
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-013.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: sideways-rl</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient with shape-margin under sideways-rl."/>
+    <style type="text/css">
+    .container {
+      writing-mode: sideways-rl;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the top. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 25%, transparent 25%);
+      shape-margin: 25%;
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the bottom. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 5%, transparent 5%);
+      shape-margin: 45%
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-014.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-014.html
new file mode 100644
index 0000000..91ba3ef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-014.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: sideways-lr</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient with shape-margin under sideways-lr."/>
+    <style type="text/css">
+    .container {
+      writing-mode: sideways-lr;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the bottom. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 25%, transparent 25%);
+      shape-margin: 25%;
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the top. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 5%, transparent 5%);
+      shape-margin: 45%
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-015.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-015.html
new file mode 100644
index 0000000..382586a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-015.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: vertical-rl and text-orientation: sideways</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient with shape-margin under vertical-rl and text-orientation: sideways."/>
+    <style type="text/css">
+    .container {
+      writing-mode: vertical-rl;
+      text-orientation: sideways;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the top. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 25%, transparent 25%);
+      shape-margin: 25%;
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the bottom. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 5%, transparent 5%);
+      shape-margin: 45%
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-016.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-016.html
new file mode 100644
index 0000000..fe45242
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-016.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>CSS Test: Test float with linear gradient under writing-mode: vertical-lr and text-orientation: sideways</title>
+    <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
+    <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shapes-from-image"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property"/>
+    <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-margin"/>
+    <link rel="match" href="reference/shape-outside-linear-gradient-001-ref.html"/>
+    <meta name="flags" content="ahem"/>
+    <meta name="assert" content="This test verifies that shape-outside respects a simple linear gradient with shape-margin under vertical-lr and text-orientation: sideways."/>
+    <style type="text/css">
+    .container {
+      writing-mode: vertical-lr;
+      text-orientation: sideways;
+      inline-size: 100px;
+      block-size: 200px;
+      background-color: red;
+      font-family: Ahem;
+      font-size: 50px;
+      line-height: 1;
+    }
+    #test {
+      color: green;
+    }
+    #float-left {
+      /* Note: In .container's writing-mode, "float: left" actually floats
+         us towards the top. */
+      float: left;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to bottom, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to bottom, green 25%, transparent 25%);
+      shape-margin: 25%;
+    }
+    #float-right {
+      /* Note: In .container's writing-mode, "float: right" actually floats
+         us towards the bottom. */
+      float: right;
+      inline-size: 100px;
+      block-size: 200px;
+      background: linear-gradient(to top, green 50%, transparent 50%);
+      shape-outside: linear-gradient(to top, green 5%, transparent 5%);
+      shape-margin: 45%
+    }
+    </style>
+  </head>
+  <body>
+    <p>
+      The test passes if you see a green square. There should be no red.
+    </p>
+    <div id="test" class="container">
+      <div id="float-left"></div>
+      x x x x
+    </div>
+    <div id="test" class="container" style="direction: rtl;">
+      <div id="float-right"></div>
+      x x x x
+    </div>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/credentials-tests.js b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/credentials-tests.js
index ef3f29b..ec0b701 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/credentials-tests.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/credentials-tests.js
@@ -68,9 +68,9 @@
     return runCredentialsTest({ workletType: worklet_type,
                                 credentials: '',
                                 origin: 'same',
-                                expectCredentialsSent: false });
+                                expectCredentialsSent: true });
   }, 'Importing a same-origin script with the default WorkletOptions should ' +
-     'not send the credentials');
+     'send the credentials');
 
   promise_test(() => {
     return runCredentialsTest({ workletType: worklet_type,
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-cert-not-found-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-cert-not-found-expected.txt
new file mode 100644
index 0000000..7fe91983
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-cert-not-found-expected.txt
@@ -0,0 +1,13 @@
+Tests the signed exchange information are available when the certificate file is not available.
+
+inspected-page.html:1 Invalid reponse code: 404
+inspected-page.html:1 Failed to fetch the certificate.
+* http://127.0.0.1:8000/loading/htxg/resources/htxg-cert-not-found.htxg
+  failed: true
+  statusCode: 200
+  resourceType: document
+* http://localhost:8000/loading/htxg/resources/not_found_cert.pem.msg
+  failed: false
+  statusCode: 404
+  resourceType: other
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-cert-not-found.js b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-cert-not-found.js
new file mode 100644
index 0000000..d44b2276
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-cert-not-found.js
@@ -0,0 +1,25 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+(async function() {
+  TestRunner.addResult('Tests the signed exchange information are available when the certificate file is not available.\n');
+  await TestRunner.loadModule('network_test_runner');
+  await TestRunner.loadModule('console_test_runner');
+  await TestRunner.showPanel('network');
+  await TestRunner.addScriptTag('/loading/htxg/resources/htxg-util.js');
+  // The timestamp of the test HTXG file is "Apr 1 2018 00:00 UTC" and valid
+  // until "Apr 8 2018 00:00 UTC".
+  await TestRunner.evaluateInPageAsync(
+    'setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"))');
+  BrowserSDK.networkLog.reset();
+  await TestRunner.addIframe('/loading/htxg/resources/htxg-cert-not-found.htxg');
+  ConsoleTestRunner.dumpConsoleMessages();
+  for (var request of BrowserSDK.networkLog.requests()) {
+    TestRunner.addResult(`* ${request.url()}`);
+    TestRunner.addResult(`  failed: ${!!request.failed}`);
+    TestRunner.addResult(`  statusCode: ${request.statusCode}`);
+    TestRunner.addResult(`  resourceType: ${request.resourceType().name()}`);
+    // TODO(crbug/830505): Check the existance of signed exchange information.
+  }
+  TestRunner.completeTest();
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation-expected.txt
index a25c5f77..ffd4415 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation-expected.txt
@@ -3,7 +3,13 @@
 * http://127.0.0.1:8000/loading/htxg/resources/htxg-location.htxg
   failed: false
   statusCode: 200
+  resourceType: signed-exchange
+* http://localhost:8000/loading/htxg/resources/127.0.0.1.pem.msg
+  failed: false
+  statusCode: 200
+  resourceType: other
 * https://www.127.0.0.1/test.html
   failed: false
   statusCode: 200
+  resourceType: document
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation-expired-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation-expired-expected.txt
index 3e60528..80f29fe6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation-expired-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation-expired-expected.txt
@@ -5,4 +5,9 @@
 * http://127.0.0.1:8000/loading/htxg/resources/htxg-location.htxg
   failed: true
   statusCode: 200
+  resourceType: document
+* http://localhost:8000/loading/htxg/resources/127.0.0.1.pem.msg
+  failed: false
+  statusCode: 200
+  resourceType: other
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation-expired.js b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation-expired.js
index 1ed38836..a4ac10bc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation-expired.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation-expired.js
@@ -18,6 +18,7 @@
     TestRunner.addResult(`* ${request.url()}`);
     TestRunner.addResult(`  failed: ${!!request.failed}`);
     TestRunner.addResult(`  statusCode: ${request.statusCode}`);
+    TestRunner.addResult(`  resourceType: ${request.resourceType().name()}`);
     // TODO(crbug/830505): Check the existance of signed exchange information.
   }
   TestRunner.completeTest();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation.js b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation.js
index 281bc76..912f7ec 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-navigation.js
@@ -18,6 +18,7 @@
     TestRunner.addResult(`* ${request.url()}`);
     TestRunner.addResult(`  failed: ${!!request.failed}`);
     TestRunner.addResult(`  statusCode: ${request.statusCode}`);
+    TestRunner.addResult(`  resourceType: ${request.resourceType().name()}`);
     // TODO(crbug/830505): Check the existance of signed exchange information.
   }
   TestRunner.completeTest();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch-expected.txt
index f941f89..4bae7f4f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch-expected.txt
@@ -3,7 +3,13 @@
 * http://127.0.0.1:8000/loading/htxg/resources/htxg-location.htxg
   failed: false
   statusCode: 200
+  resourceType: signed-exchange
+* http://localhost:8000/loading/htxg/resources/127.0.0.1.pem.msg
+  failed: false
+  statusCode: 200
+  resourceType: other
 * https://www.127.0.0.1/test.html
   failed: false
   statusCode: 200
+  resourceType: other
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch-expired-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch-expired-expected.txt
index e1a5cc2..29c86a6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch-expired-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch-expired-expected.txt
@@ -3,4 +3,9 @@
 * http://127.0.0.1:8000/loading/htxg/resources/htxg-location.htxg
   failed: true
   statusCode: 200
+  resourceType: other
+* http://localhost:8000/loading/htxg/resources/127.0.0.1.pem.msg
+  failed: false
+  statusCode: 200
+  resourceType: other
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch-expired.js b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch-expired.js
index e8195e5..730d183 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch-expired.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch-expired.js
@@ -35,6 +35,7 @@
     TestRunner.addResult(`* ${request.url()}`);
     TestRunner.addResult(`  failed: ${!!request.failed}`);
     TestRunner.addResult(`  statusCode: ${request.statusCode}`);
+    TestRunner.addResult(`  resourceType: ${request.resourceType().name()}`);
     // TODO(crbug/830505): Check the existance of signed exchange information.
   }
   TestRunner.completeTest();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch.js b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch.js
index b8b98de..97f7000 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/htxg/htxg-prefetch.js
@@ -35,6 +35,7 @@
     TestRunner.addResult(`* ${request.url()}`);
     TestRunner.addResult(`  failed: ${!!request.failed}`);
     TestRunner.addResult(`  statusCode: ${request.statusCode}`);
+    TestRunner.addResult(`  resourceType: ${request.resourceType().name()}`);
     // TODO(crbug/830505): Check the existance of signed exchange information.
   }
   TestRunner.completeTest();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/network/network-toggle-type-filter-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/network/network-toggle-type-filter-expected.txt
index ac15572..b7122ed 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/network/network-toggle-type-filter-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/network/network-toggle-type-filter-expected.txt
@@ -2,44 +2,44 @@
 
 
 Clicked 'all' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: true, snippet: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true, sm-script: true, sm-stylesheet: true, manifest: true
+Filter: xhr: true, fetch: true, eventsource: true, script: true, snippet: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true, sm-script: true, sm-stylesheet: true, manifest: true, signed-exchange: true
 
 Clicked 'Documents' button.
-Filter: xhr: false, fetch: false, eventsource: false, script: false, snippet: false, stylesheet: false, image: false, media: false, font: false, document: true, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false, manifest: false
+Filter: xhr: false, fetch: false, eventsource: false, script: false, snippet: false, stylesheet: false, image: false, media: false, font: false, document: true, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false, manifest: false, signed-exchange: false
 
 Clicked 'Documents' button.
-Filter: xhr: false, fetch: false, eventsource: false, script: false, snippet: false, stylesheet: false, image: false, media: false, font: false, document: true, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false, manifest: false
+Filter: xhr: false, fetch: false, eventsource: false, script: false, snippet: false, stylesheet: false, image: false, media: false, font: false, document: true, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false, manifest: false, signed-exchange: false
 
 Clicked 'Scripts' button.
-Filter: xhr: false, fetch: false, eventsource: false, script: true, snippet: true, stylesheet: false, image: false, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: true, sm-stylesheet: false, manifest: false
+Filter: xhr: false, fetch: false, eventsource: false, script: true, snippet: true, stylesheet: false, image: false, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: true, sm-stylesheet: false, manifest: false, signed-exchange: false
 
 Toggled 'all' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: true, snippet: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true, sm-script: true, sm-stylesheet: true, manifest: true
+Filter: xhr: true, fetch: true, eventsource: true, script: true, snippet: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true, sm-script: true, sm-stylesheet: true, manifest: true, signed-exchange: true
 
 Toggled 'all' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: true, snippet: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true, sm-script: true, sm-stylesheet: true, manifest: true
+Filter: xhr: true, fetch: true, eventsource: true, script: true, snippet: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true, sm-script: true, sm-stylesheet: true, manifest: true, signed-exchange: true
 
 Toggled 'Stylesheets' button.
-Filter: xhr: false, fetch: false, eventsource: false, script: false, snippet: false, stylesheet: true, image: false, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: true, manifest: false
+Filter: xhr: false, fetch: false, eventsource: false, script: false, snippet: false, stylesheet: true, image: false, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: true, manifest: false, signed-exchange: false
 
 Toggled 'Images' button.
-Filter: xhr: false, fetch: false, eventsource: false, script: false, snippet: false, stylesheet: true, image: true, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: true, manifest: false
+Filter: xhr: false, fetch: false, eventsource: false, script: false, snippet: false, stylesheet: true, image: true, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: true, manifest: false, signed-exchange: false
 
 Toggled 'Stylesheets' button.
-Filter: xhr: false, fetch: false, eventsource: false, script: false, snippet: false, stylesheet: false, image: true, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false, manifest: false
+Filter: xhr: false, fetch: false, eventsource: false, script: false, snippet: false, stylesheet: false, image: true, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false, manifest: false, signed-exchange: false
 
 Clicked 'XHR and Fetch' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: false, snippet: false, stylesheet: false, image: false, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false, manifest: false
+Filter: xhr: true, fetch: true, eventsource: true, script: false, snippet: false, stylesheet: false, image: false, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false, manifest: false, signed-exchange: false
 
 Toggled 'Fonts' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: false, snippet: false, stylesheet: false, image: false, media: false, font: true, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false, manifest: false
+Filter: xhr: true, fetch: true, eventsource: true, script: false, snippet: false, stylesheet: false, image: false, media: false, font: true, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false, manifest: false, signed-exchange: false
 
 Toggled 'WebSockets' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: false, snippet: false, stylesheet: false, image: false, media: false, font: true, document: false, texttrack: false, websocket: true, other: false, sm-script: false, sm-stylesheet: false, manifest: false
+Filter: xhr: true, fetch: true, eventsource: true, script: false, snippet: false, stylesheet: false, image: false, media: false, font: true, document: false, texttrack: false, websocket: true, other: false, sm-script: false, sm-stylesheet: false, manifest: false, signed-exchange: false
 
 Toggled 'Media' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: false, snippet: false, stylesheet: false, image: false, media: true, font: true, document: false, texttrack: false, websocket: true, other: false, sm-script: false, sm-stylesheet: false, manifest: false
+Filter: xhr: true, fetch: true, eventsource: true, script: false, snippet: false, stylesheet: false, image: false, media: true, font: true, document: false, texttrack: false, websocket: true, other: false, sm-script: false, sm-stylesheet: false, manifest: false, signed-exchange: false
 
 Clicked 'all' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: true, snippet: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true, sm-script: true, sm-stylesheet: true, manifest: true
+Filter: xhr: true, fetch: true, eventsource: true, script: true, snippet: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true, sm-script: true, sm-stylesheet: true, manifest: true, signed-exchange: true
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/htxg/htxg-expired.html b/third_party/WebKit/LayoutTests/http/tests/loading/htxg/htxg-expired.html
index 6dff422..b74f8fa 100644
--- a/third_party/WebKit/LayoutTests/http/tests/loading/htxg/htxg-expired.html
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/htxg/htxg-expired.html
@@ -6,6 +6,8 @@
 <body>
 <script>
 promise_test(async (t) => {
+  await waitUntilDidFinishLoadForFrame;
+
   // The timestamp of the test HTXG file is "Apr 1 2018 00:00 UTC" and valid
   // until "Apr 8 2018 00:00 UTC". So in Apr 10, the page load should fail.
   await setSignedExchangeVerificationTime(new Date("Apr 10 2018 00:01 UTC"));
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/htxg/htxg-location-origin-trial.html b/third_party/WebKit/LayoutTests/http/tests/loading/htxg/htxg-location-origin-trial.html
new file mode 100644
index 0000000..45f0292
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/htxg/htxg-location-origin-trial.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Location of SignedHTTPExchange with Origin-Trial header</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="./resources/htxg-util.js"></script>
+<body>
+<script>
+promise_test(async (t) => {
+  await waitUntilDidFinishLoadForFrame;
+
+  // The timestamp of the test HTXG file is "Apr 1 2018 00:00 UTC" and valid
+  // until "Apr 8 2018 00:00 UTC".
+  await setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"));
+
+  const event = await new Promise(async (resolve, reject) => {
+    // We can't catch the network error on iframe. So we use the timer.
+    t.step_timeout(() => reject('timeout'), 1000);
+
+    const frame =
+        await withIframe('resources/htxg-location-origin-trial.php',
+                         'htxg_iframe');
+    const channel = new MessageChannel();
+    channel.port1.onmessage = resolve;
+    frame.contentWindow.postMessage(
+        {port: channel.port2}, '*', [channel.port2]);
+  });
+  assert_equals(event.data.location, 'https://www.127.0.0.1/test.html');
+}, 'Location of SignedHTTPExchange with Origin-Trial header');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/htxg/htxg-location.html b/third_party/WebKit/LayoutTests/http/tests/loading/htxg/htxg-location.html
index ed6326d..859b4e7 100644
--- a/third_party/WebKit/LayoutTests/http/tests/loading/htxg/htxg-location.html
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/htxg/htxg-location.html
@@ -6,6 +6,8 @@
 <body>
 <script>
 promise_test(async (t) => {
+  await waitUntilDidFinishLoadForFrame;
+
   // The timestamp of the test HTXG file is "Apr 1 2018 00:00 UTC" and valid
   // until "Apr 8 2018 00:00 UTC".
   await setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"));
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/README.md b/third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/README.md
index 78848b5b..a6b84788 100644
--- a/third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/README.md
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/README.md
@@ -34,4 +34,18 @@
   -expire 168h \
   -o htxg-location.htxg \
   -miRecordSize 100
+
+# Generate the signed exchange file which certificate file is not available.
+gen-signedexchange \
+  -uri https://www.127.0.0.1/not_found_cert.html \
+  -status 200 \
+  -content htxg-location.html \
+  -certificate ../../../../../../../blink/tools/blinkpy/third_party/wpt/certs/127.0.0.1.pem \
+  -certUrl http://localhost:8000/loading/htxg/resources/not_found_cert.pem.msg \
+  -validityUrl http://localhost:8000/loading/htxg/resources/not_found_cert.validity.msg \
+  -privateKey ../../../../../../../blink/tools/blinkpy/third_party/wpt/certs/127.0.0.1.key\
+  -date 2018-04-01T00:00:00Z \
+  -expire 168h \
+  -o htxg-cert-not-found.htxg \
+  -miRecordSize 100
 ```
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/htxg-cert-not-found.htxg b/third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/htxg-cert-not-found.htxg
new file mode 100644
index 0000000..d769e74
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/htxg-cert-not-found.htxg
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/htxg-location-origin-trial.php b/third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/htxg-location-origin-trial.php
new file mode 100644
index 0000000..98168681
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/htxg-location-origin-trial.php
@@ -0,0 +1,10 @@
+<?php
+header('HTTP/1.0 200 OK');
+// generate_token.py http://127.0.0.1:8000 SignedHTTPExchange --expire-timestamp=2000000000
+header("Origin-Trial: AgeFm+W/+DvAEn/vDjtqgd5PQX73YxKJLGBwLp14SiMjKFNTEUK2Bx5R3gH23JOfP+IL2EGNj+x9uhzh2krVRgsAAABaeyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiU2lnbmVkSFRUUEV4Y2hhbmdlIiwgImV4cGlyeSI6IDIwMDAwMDAwMDB9");
+header("Content-Type: application/signed-exchange;v=b0");
+$name = 'htxg-location.htxg';
+$fp = fopen($name, 'rb');
+header("Content-Length: " . filesize($name));
+fpassthru($fp);
+?>
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/htxg-util.js b/third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/htxg-util.js
index 936ba4c..dd21e89 100644
--- a/third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/htxg-util.js
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/htxg-util.js
@@ -19,6 +19,12 @@
   });
 }
 
+// Used to delay the iframe creation after "didFinishLoadForFrame" is printed.
+// This is intended to avoid the flakiness of the result outputs.
+const waitUntilDidFinishLoadForFrame = new Promise((resolve) => {
+  window.addEventListener('load', () => setTimeout(resolve, 0));
+});
+
 const mojoBindingsLoaded = (async () => {
   await loadScript('/gen/layout_test_data/mojo/public/js/mojo_bindings.js');
   mojo.config.autoLoadMojomDeps = false;
diff --git a/third_party/WebKit/LayoutTests/http/tests/websocket/workers/no-onmessage-in-sync-op-expected.txt b/third_party/WebKit/LayoutTests/http/tests/websocket/workers/no-onmessage-in-sync-op-expected.txt
index dd7c3fcc..b669df63 100644
--- a/third_party/WebKit/LayoutTests/http/tests/websocket/workers/no-onmessage-in-sync-op-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/websocket/workers/no-onmessage-in-sync-op-expected.txt
@@ -2,7 +2,6 @@
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
-INFO: Waiting for two seconds to make sure we receive messages from the server.
 PASS PASS: closeEvent.wasClean is true
 PASS PASS: event.length is 9
 PASS PASS: events[0] is "Got bufferedAmount: 0"
diff --git a/third_party/WebKit/LayoutTests/http/tests/websocket/workers/resources/no-onmessage-in-sync-op.js b/third_party/WebKit/LayoutTests/http/tests/websocket/workers/resources/no-onmessage-in-sync-op.js
index 983e1e2..f06d564 100644
--- a/third_party/WebKit/LayoutTests/http/tests/websocket/workers/resources/no-onmessage-in-sync-op.js
+++ b/third_party/WebKit/LayoutTests/http/tests/websocket/workers/resources/no-onmessage-in-sync-op.js
@@ -14,11 +14,10 @@
 
 ws.onopen = function()
 {
-    // After handshake, the server will send three messages immediately, but they should not be received
-    // until we exit this event loop.
-    postMessage("INFO: Waiting for two seconds to make sure we receive messages from the server.");
-    var start = (new Date()).getTime();
-    while ((new Date()).getTime() - start < 2000) {}
+    // After handshake, the server will send three messages immediately, but
+    // the events should not be fired until we return from this event handler.
+    var start = performance.now();
+    while (performance.now() - start < 200) {}
 
     var bufferedAmount = ws.bufferedAmount;
     events.push("Got bufferedAmount: " + bufferedAmount);
diff --git a/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLImageElement.html b/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLImageElement.html
index 2d1d7524..fa832a6 100644
--- a/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLImageElement.html
+++ b/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLImageElement.html
@@ -42,7 +42,12 @@
                       {type : 'eye', locations : [{x : 4.0, y : 5.0}]},
                       "landmark #1");
   assert_equals(detectionResult[0].landmarks[1].locations.length, 8,
-                "Number of locations along the landmark");
+                "Number of locations along eye");
+  assert_object_equals(detectionResult[1].landmarks[0],
+                      {type : 'nose', locations : [{x : 100.0, y : 50.0}]},
+                      "landmark #2");
+  assert_equals(detectionResult[1].landmarks[1].locations.length, 9,
+                "Number of locations along nose");
 }
 
 function BarcodeDetectorDetectionResultTest(detectionResult, mock) {
diff --git a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js
index b403da4..1971e0f5 100644
--- a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js
+++ b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js
@@ -59,7 +59,18 @@
         },
         {
           boundingBox: {x: 2.0, y: 2.0, width: 200.0, height: 200.0},
-          landmarks: []
+          landmarks: [{
+            type: shapeDetection.mojom.LandmarkType.NOSE,
+            locations: [{x: 100.0, y: 50.0}]
+          },
+          {
+            type: shapeDetection.mojom.LandmarkType.NOSE,
+            locations: [
+              {x: 80.0, y: 50.0}, {x: 70.0, y: 60.0}, {x: 60.0, y: 70.0},
+              {x: 70.0, y: 60.0}, {x: 80.0, y: 70.0}, {x: 90.0, y: 80.0},
+              {x: 100.0, y: 70.0}, {x: 90.0, y: 60.0}, {x: 80.0, y: 50.0}
+            ]
+          }]
         },
         {
           boundingBox: {x: 3.0, y: 3.0, width: 300.0, height: 300.0},
diff --git a/third_party/WebKit/LayoutTests/virtual/htxg-origin-trial-with-network-service/http/tests/loading/htxg/README.txt b/third_party/WebKit/LayoutTests/virtual/htxg-origin-trial-with-network-service/http/tests/loading/htxg/README.txt
new file mode 100644
index 0000000..2524f8a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/htxg-origin-trial-with-network-service/http/tests/loading/htxg/README.txt
@@ -0,0 +1 @@
+This directory is for testing the SignedHTTPExchangeOriginTrial feature.
diff --git a/third_party/WebKit/LayoutTests/virtual/htxg-origin-trial-with-network-service/http/tests/loading/htxg/htxg-location-expected.txt b/third_party/WebKit/LayoutTests/virtual/htxg-origin-trial-with-network-service/http/tests/loading/htxg/htxg-location-expected.txt
new file mode 100644
index 0000000..aa831eeb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/htxg-origin-trial-with-network-service/http/tests/loading/htxg/htxg-location-expected.txt
@@ -0,0 +1,13 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+main frame - didReceiveTitle: Location of SignedHTTPExchange
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+frame "htxg_iframe" - didReceiveTitle: 
+frame "htxg_iframe" - didStartProvisionalLoadForFrame
+frame "htxg_iframe" - didFailProvisionalLoadWithError
+This is a testharness.js-based test.
+FAIL Location of SignedHTTPExchange promise_test: Unhandled rejection with value: "timeout"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/htxg-origin-trial/http/tests/loading/htxg/README.txt b/third_party/WebKit/LayoutTests/virtual/htxg-origin-trial/http/tests/loading/htxg/README.txt
new file mode 100644
index 0000000..2524f8a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/htxg-origin-trial/http/tests/loading/htxg/README.txt
@@ -0,0 +1 @@
+This directory is for testing the SignedHTTPExchangeOriginTrial feature.
diff --git a/third_party/WebKit/LayoutTests/virtual/htxg-origin-trial/http/tests/loading/htxg/htxg-location-expected.txt b/third_party/WebKit/LayoutTests/virtual/htxg-origin-trial/http/tests/loading/htxg/htxg-location-expected.txt
new file mode 100644
index 0000000..aa831eeb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/htxg-origin-trial/http/tests/loading/htxg/htxg-location-expected.txt
@@ -0,0 +1,13 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+main frame - didReceiveTitle: Location of SignedHTTPExchange
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+frame "htxg_iframe" - didReceiveTitle: 
+frame "htxg_iframe" - didStartProvisionalLoadForFrame
+frame "htxg_iframe" - didFailProvisionalLoadWithError
+This is a testharness.js-based test.
+FAIL Location of SignedHTTPExchange promise_test: Unhandled rejection with value: "timeout"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 7216b60..5f52eb9 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -155,7 +155,6 @@
     "platform/modules/notifications/web_notification_action.h",
     "platform/modules/notifications/web_notification_constants.h",
     "platform/modules/notifications/web_notification_data.h",
-    "platform/modules/notifications/web_notification_manager.h",
     "platform/modules/notifications/web_notification_resources.h",
     "platform/modules/payments/web_payment_currency_amount.h",
     "platform/modules/payments/web_payment_details_modifier.h",
diff --git a/third_party/blink/public/platform/modules/notifications/web_notification_manager.h b/third_party/blink/public/platform/modules/notifications/web_notification_manager.h
deleted file mode 100644
index 8cd35c9..0000000
--- a/third_party/blink/public/platform/modules/notifications/web_notification_manager.h
+++ /dev/null
@@ -1,64 +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 THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_NOTIFICATIONS_WEB_NOTIFICATION_MANAGER_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_NOTIFICATIONS_WEB_NOTIFICATION_MANAGER_H_
-
-#include <stdint.h>
-#include <memory>
-#include "third_party/blink/public/platform/modules/notifications/web_notification_data.h"
-#include "third_party/blink/public/platform/modules/notifications/web_notification_resources.h"
-#include "third_party/blink/public/platform/web_callbacks.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_vector.h"
-
-namespace blink {
-
-class WebSecurityOrigin;
-class WebServiceWorkerRegistration;
-
-// Structure representing the info associated with a persistent notification.
-struct WebPersistentNotificationInfo {
-  WebString notification_id;
-  WebNotificationData data;
-};
-
-using WebNotificationGetCallbacks =
-    WebCallbacks<const WebVector<WebPersistentNotificationInfo>&, void>;
-using WebNotificationShowCallbacks = WebCallbacks<void, void>;
-
-// Provides the services to show platform notifications to the user.
-class WebNotificationManager {
- public:
-  virtual ~WebNotificationManager() = default;
-
-  // Shows a persistent notification on the user's system. These notifications
-  // will have their events delivered to a Service Worker rather than the
-  // object's delegate. Will take ownership of the WebNotificationShowCallbacks
-  // object.
-  virtual void ShowPersistent(
-      const WebSecurityOrigin&,
-      const WebNotificationData&,
-      std::unique_ptr<WebNotificationResources>,
-      WebServiceWorkerRegistration*,
-      std::unique_ptr<WebNotificationShowCallbacks>) = 0;
-
-  // Asynchronously gets the persistent notifications belonging to the Service
-  // Worker Registration.  If |filterTag| is not an empty string, only the
-  // notification with the given tag will be considered. Will take ownership of
-  // the WebNotificationGetCallbacks object.
-  virtual void GetNotifications(
-      const WebString& filter_tag,
-      WebServiceWorkerRegistration*,
-      std::unique_ptr<WebNotificationGetCallbacks>) = 0;
-
-  // Closes a persistent notification identified by its notification Id.
-  virtual void ClosePersistent(const WebSecurityOrigin&,
-                               const WebString& tag,
-                               const WebString& notification_id) = 0;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_NOTIFICATIONS_WEB_NOTIFICATION_MANAGER_H_
diff --git a/third_party/blink/public/platform/task_type.h b/third_party/blink/public/platform/task_type.h
index ffe051a..3104cdf 100644
--- a/third_party/blink/public/platform/task_type.h
+++ b/third_party/blink/public/platform/task_type.h
@@ -165,6 +165,10 @@
   // Tasks related to animation like blinking caret or CSS animation.
   kInternalAnimation = 34,
 
+  // Tasks related to workers. Tasks with this type are mainly posted by:
+  // * //third_party/blink/renderer/core/workers
+  kInternalWorker = 36,
+
   ///////////////////////////////////////
   // The following task types are DEPRECATED! Use kInternal* instead.
   ///////////////////////////////////////
@@ -173,7 +177,7 @@
   // should be very limited.
   kUnthrottled = 25,
 
-  kCount = 36,
+  kCount = 37,
 };
 
 }  // namespace blink
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom
index 1d5c2e93..71480e2 100644
--- a/third_party/blink/public/platform/web_feature.mojom
+++ b/third_party/blink/public/platform/web_feature.mojom
@@ -1914,6 +1914,7 @@
   kKeyboardApiGetLayoutMap = 2432,
   kWebRtcVaapiHWVP8Encoding = 2433,
   kPerformanceResourceTimingInitiatorType = 2434,
+  kPaymentRequestInvalidCurrencyCode = 2435,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
index 0ab0037..09f3c5d 100644
--- a/third_party/blink/public/platform/web_runtime_features.h
+++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -104,7 +104,6 @@
   BLINK_PLATFORM_EXPORT static void EnableNotificationConstructor(bool);
   BLINK_PLATFORM_EXPORT static void EnableNotificationContentImage(bool);
   BLINK_PLATFORM_EXPORT static void EnableNotifications(bool);
-  BLINK_PLATFORM_EXPORT static void EnableNotificationsWithMojo(bool);
   BLINK_PLATFORM_EXPORT static void EnableOnDeviceChange(bool);
   BLINK_PLATFORM_EXPORT static void EnableOrientationEvent(bool);
   BLINK_PLATFORM_EXPORT static void EnableOriginManifest(bool);
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_registry.cc b/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
index c8d3fe9..2b16ced 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
@@ -113,6 +113,7 @@
   visitor->Trace(v0_);
   visitor->Trace(upgrade_candidates_);
   visitor->Trace(when_defined_promise_map_);
+  visitor->Trace(reaction_stack_);
   ScriptWrappable::Trace(visitor);
 }
 
diff --git a/third_party/blink/renderer/core/html/forms/text_control_element_test.cc b/third_party/blink/renderer/core/html/forms/text_control_element_test.cc
index e3f8b03..8b2b775 100644
--- a/third_party/blink/renderer/core/html/forms/text_control_element_test.cc
+++ b/third_party/blink/renderer/core/html/forms/text_control_element_test.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/editing/position.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
@@ -78,13 +79,37 @@
 }
 
 TEST_F(TextControlElementTest, IndexForPosition) {
-  HTMLInputElement* input =
-      ToHTMLInputElement(GetDocument().getElementById("input"));
-  input->setValue("Hello");
-  HTMLElement* inner_editor = input->InnerEditorElement();
+  Input().setValue("Hello");
+  HTMLElement* inner_editor = Input().InnerEditorElement();
   EXPECT_EQ(5u, TextControlElement::IndexForPosition(
                     inner_editor,
                     Position(inner_editor, PositionAnchorType::kAfterAnchor)));
 }
 
+TEST_F(TextControlElementTest, ReadOnlyAttributeChangeEditability) {
+  Input().setAttribute(HTMLNames::styleAttr, "all:initial");
+  Input().setAttribute(HTMLNames::readonlyAttr, "");
+  GetDocument().View()->UpdateAllLifecyclePhases();
+  EXPECT_EQ(EUserModify::kReadOnly,
+            Input().InnerEditorElement()->GetComputedStyle()->UserModify());
+
+  Input().removeAttribute(HTMLNames::readonlyAttr);
+  GetDocument().View()->UpdateAllLifecyclePhases();
+  EXPECT_EQ(EUserModify::kReadWritePlaintextOnly,
+            Input().InnerEditorElement()->GetComputedStyle()->UserModify());
+}
+
+TEST_F(TextControlElementTest, DisabledAttributeChangeEditability) {
+  Input().setAttribute(HTMLNames::styleAttr, "all:initial");
+  Input().setAttribute(HTMLNames::disabledAttr, "");
+  GetDocument().View()->UpdateAllLifecyclePhases();
+  EXPECT_EQ(EUserModify::kReadOnly,
+            Input().InnerEditorElement()->GetComputedStyle()->UserModify());
+
+  Input().removeAttribute(HTMLNames::disabledAttr);
+  GetDocument().View()->UpdateAllLifecyclePhases();
+  EXPECT_EQ(EUserModify::kReadWritePlaintextOnly,
+            Input().InnerEditorElement()->GetComputedStyle()->UserModify());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/text_field_input_type.cc b/third_party/blink/renderer/core/html/forms/text_field_input_type.cc
index c5e2fbf1..e48cbb4 100644
--- a/third_party/blink/renderer/core/html/forms/text_field_input_type.cc
+++ b/third_party/blink/renderer/core/html/forms/text_field_input_type.cc
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/core/html/forms/text_field_input_type.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/exception_state.h"
+#include "third_party/blink/renderer/core/css/style_change_reason.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/events/before_text_inserted_event.h"
@@ -366,14 +367,20 @@
   UpdateView();
 }
 
-void TextFieldInputType::DisabledAttributeChanged() {
+void TextFieldInputType::DisabledOrReadonlyAttributeChanged(
+    const QualifiedName& attr) {
   if (SpinButtonElement* spin_button = GetSpinButtonElement())
     spin_button->ReleaseCapture();
+  GetElement().InnerEditorElement()->SetNeedsStyleRecalc(
+      kLocalStyleChange, StyleChangeReasonForTracing::FromAttribute(attr));
+}
+
+void TextFieldInputType::DisabledAttributeChanged() {
+  DisabledOrReadonlyAttributeChanged(disabledAttr);
 }
 
 void TextFieldInputType::ReadonlyAttributeChanged() {
-  if (SpinButtonElement* spin_button = GetSpinButtonElement())
-    spin_button->ReleaseCapture();
+  DisabledOrReadonlyAttributeChanged(readonlyAttr);
 }
 
 bool TextFieldInputType::SupportsReadOnly() const {
diff --git a/third_party/blink/renderer/core/html/forms/text_field_input_type.h b/third_party/blink/renderer/core/html/forms/text_field_input_type.h
index fe8ca84..909b56b 100644
--- a/third_party/blink/renderer/core/html/forms/text_field_input_type.h
+++ b/third_party/blink/renderer/core/html/forms/text_field_input_type.h
@@ -101,6 +101,7 @@
   void SpinButtonDidReleaseMouseCapture(SpinButtonElement::EventDispatch) final;
 
   SpinButtonElement* GetSpinButtonElement() const;
+  void DisabledOrReadonlyAttributeChanged(const QualifiedName&);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index 3434b51..138921e 100644
--- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -4347,6 +4347,7 @@
       EventSource
       WebSocket
       Manifest
+      SignedExchange
       Other
 
   # Unique frame identifier.
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
index 7a80a53..7f881fe3 100644
--- a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
@@ -400,6 +400,8 @@
       return protocol::Page::ResourceTypeEnum::WebSocket;
     case kManifestResource:
       return protocol::Page::ResourceTypeEnum::Manifest;
+    case kSignedExchangeResource:
+      return protocol::Page::ResourceTypeEnum::SignedExchange;
     case kOtherResource:
       return protocol::Page::ResourceTypeEnum::Other;
   }
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.h b/third_party/blink/renderer/core/inspector/inspector_page_agent.h
index 702829c..33444ec 100644
--- a/third_party/blink/renderer/core/inspector/inspector_page_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.h
@@ -81,6 +81,7 @@
     kEventSourceResource,
     kWebSocketResource,
     kManifestResource,
+    kSignedExchangeResource,
     kOtherResource
   };
 
diff --git a/third_party/blink/renderer/core/layout/layout_list_item.cc b/third_party/blink/renderer/core/layout/layout_list_item.cc
index c0b7c3b..d6928c51 100644
--- a/third_party/blink/renderer/core/layout/layout_list_item.cc
+++ b/third_party/blink/renderer/core/layout/layout_list_item.cc
@@ -266,10 +266,10 @@
   if (marker_parent != line_box_parent) {
     marker_->Remove();
     line_box_parent->AddChild(marker_, FirstNonMarkerChild(line_box_parent));
-    // TODO(rhogan): lineBoxParent and markerParent may be deleted by addChild,
-    // so they are not safe to reference here.
-    // Once we have a safe way of referencing them delete markerParent if it is
-    // an empty anonymous block.
+    // TODO(rhogan): line_box_parent and marker_parent may be deleted by
+    // AddChild, so they are not safe to reference here. Once we have a safe way
+    // of referencing them delete marker_parent if it is an empty anonymous
+    // block.
     marker_->UpdateMarginsAndContent();
     return true;
   }
diff --git a/third_party/blink/renderer/core/layout/layout_list_marker.cc b/third_party/blink/renderer/core/layout/layout_list_marker.cc
index 7d67484..37451f7e 100644
--- a/third_party/blink/renderer/core/layout/layout_list_marker.cc
+++ b/third_party/blink/renderer/core/layout/layout_list_marker.cc
@@ -177,16 +177,14 @@
 }
 
 void LayoutListMarker::UpdateMarginsAndContent() {
-  UpdateContent();
-  UpdateMargins();
+  if (PreferredLogicalWidthsDirty())
+    ComputePreferredLogicalWidths();
+  else
+    UpdateMargins();
 }
 
 void LayoutListMarker::UpdateContent() {
-  // FIXME: This if-statement is just a performance optimization, but it's messy
-  // to use the preferredLogicalWidths dirty bit for this.
-  // It's unclear if this is a premature optimization.
-  if (!PreferredLogicalWidthsDirty())
-    return;
+  DCHECK(PreferredLogicalWidthsDirty());
 
   text_ = "";
 
@@ -282,8 +280,16 @@
     std::tie(margin_start, margin_end) =
         InlineMarginsForOutside(style, IsImage(), MinPreferredLogicalWidth());
   }
-  MutableStyleRef().SetMarginStart(Length(margin_start, kFixed));
-  MutableStyleRef().SetMarginEnd(Length(margin_end, kFixed));
+
+  Length start_length(margin_start, kFixed);
+  Length end_length(margin_end, kFixed);
+
+  if (start_length != style.MarginStart() || end_length != style.MarginEnd()) {
+    scoped_refptr<ComputedStyle> new_style = ComputedStyle::Clone(style);
+    new_style->SetMarginStart(start_length);
+    new_style->SetMarginEnd(end_length);
+    SetStyleInternal(std::move(new_style));
+  }
 }
 
 std::pair<LayoutUnit, LayoutUnit> LayoutListMarker::InlineMarginsForInside(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
index 56477f84..aee6d96 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
@@ -29,8 +29,6 @@
     bool is_fixed_size_block,
     bool fixed_size_block_is_definite,
     bool is_shrink_to_fit,
-    bool is_inline_direction_triggers_scrollbar,
-    bool is_block_direction_triggers_scrollbar,
     NGFragmentationType block_direction_fragmentation_type,
     bool separate_leading_fragmentainer_margins,
     bool is_new_fc,
@@ -54,10 +52,6 @@
       is_fixed_size_block_(is_fixed_size_block),
       fixed_size_block_is_definite_(fixed_size_block_is_definite),
       is_shrink_to_fit_(is_shrink_to_fit),
-      is_inline_direction_triggers_scrollbar_(
-          is_inline_direction_triggers_scrollbar),
-      is_block_direction_triggers_scrollbar_(
-          is_block_direction_triggers_scrollbar),
       block_direction_fragmentation_type_(block_direction_fragmentation_type),
       separate_leading_fragmentainer_margins_(
           separate_leading_fragmentainer_margins),
@@ -177,10 +171,6 @@
 
   return builder.SetAvailableSize(available_size)
       .SetPercentageResolutionSize(percentage_size)
-      .SetIsInlineDirectionTriggersScrollbar(
-          box.StyleRef().OverflowInlineDirection() == EOverflow::kAuto)
-      .SetIsBlockDirectionTriggersScrollbar(
-          box.StyleRef().OverflowBlockDirection() == EOverflow::kAuto)
       .SetIsFixedSizeInline(fixed_inline)
       .SetIsFixedSizeBlock(fixed_block)
       .SetFixedSizeBlockIsDefinite(fixed_block_is_definite)
@@ -230,10 +220,6 @@
          is_fixed_size_inline_ == other.is_fixed_size_inline_ &&
          is_fixed_size_block_ == other.is_fixed_size_block_ &&
          is_shrink_to_fit_ == other.is_shrink_to_fit_ &&
-         is_inline_direction_triggers_scrollbar_ ==
-             other.is_inline_direction_triggers_scrollbar_ &&
-         is_block_direction_triggers_scrollbar_ ==
-             other.is_block_direction_triggers_scrollbar_ &&
          block_direction_fragmentation_type_ ==
              other.block_direction_fragmentation_type_ &&
          is_new_fc_ == other.is_new_fc_ &&
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
index 110c724..b68c0dc 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -116,18 +116,6 @@
   // Also note this is true only when the document has ':first-line' rules.
   bool UseFirstLineStyle() const { return use_first_line_style_; }
 
-  // Whether exceeding the AvailableSize() triggers the presence of a scrollbar
-  // for the indicated direction.
-  // If exceeded the current layout should be aborted and invoked again with a
-  // constraint space modified to reserve space for a scrollbar.
-  bool IsInlineDirectionTriggersScrollbar() const {
-    return is_inline_direction_triggers_scrollbar_;
-  }
-
-  bool IsBlockDirectionTriggersScrollbar() const {
-    return is_block_direction_triggers_scrollbar_;
-  }
-
   // Some layout modes “stretch” their children to a fixed size (e.g. flex,
   // grid). These flags represented whether a layout needs to produce a
   // fragment that satisfies a fixed constraint in the inline and block
@@ -235,8 +223,6 @@
                     bool is_fixed_size_block,
                     bool fixed_size_block_is_definite,
                     bool is_shrink_to_fit,
-                    bool is_inline_direction_triggers_scrollbar,
-                    bool is_block_direction_triggers_scrollbar,
                     NGFragmentationType block_direction_fragmentation_type,
                     bool separate_leading_fragmentainer_margins_,
                     bool is_new_fc,
@@ -264,9 +250,6 @@
 
   unsigned is_shrink_to_fit_ : 1;
 
-  unsigned is_inline_direction_triggers_scrollbar_ : 1;
-  unsigned is_block_direction_triggers_scrollbar_ : 1;
-
   unsigned block_direction_fragmentation_type_ : 2;
   unsigned separate_leading_fragmentainer_margins_ : 1;
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc
index ec417f9..b537ae55 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc
@@ -25,8 +25,6 @@
       is_fixed_size_block_(false),
       fixed_size_block_is_definite_(true),
       is_shrink_to_fit_(false),
-      is_inline_direction_triggers_scrollbar_(false),
-      is_block_direction_triggers_scrollbar_(false),
       fragmentation_type_(kFragmentNone),
       separate_leading_fragmentainer_margins_(false),
       is_new_fc_(false),
@@ -108,22 +106,6 @@
   return *this;
 }
 
-NGConstraintSpaceBuilder&
-NGConstraintSpaceBuilder::SetIsInlineDirectionTriggersScrollbar(
-    bool is_inline_direction_triggers_scrollbar) {
-  is_inline_direction_triggers_scrollbar_ =
-      is_inline_direction_triggers_scrollbar;
-  return *this;
-}
-
-NGConstraintSpaceBuilder&
-NGConstraintSpaceBuilder::SetIsBlockDirectionTriggersScrollbar(
-    bool is_block_direction_triggers_scrollbar) {
-  is_block_direction_triggers_scrollbar_ =
-      is_block_direction_triggers_scrollbar;
-  return *this;
-}
-
 NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetFragmentationType(
     NGFragmentationType fragmentation_type) {
   fragmentation_type_ = fragmentation_type;
@@ -230,8 +212,6 @@
         initial_containing_block_size_, fragmentainer_block_size_,
         fragmentainer_space_at_bfc_start_, is_fixed_size_inline_,
         is_fixed_size_block_, fixed_size_block_is_definite_, is_shrink_to_fit_,
-        is_inline_direction_triggers_scrollbar_,
-        is_block_direction_triggers_scrollbar_,
         static_cast<NGFragmentationType>(fragmentation_type_),
         separate_leading_fragmentainer_margins_, is_new_fc_, is_anonymous_,
         use_first_line_style_, adjoining_floats_, margin_strut, bfc_offset,
@@ -245,8 +225,6 @@
       initial_containing_block_size_, fragmentainer_block_size_,
       fragmentainer_space_at_bfc_start_, is_fixed_size_block_,
       is_fixed_size_inline_, true, is_shrink_to_fit_,
-      is_block_direction_triggers_scrollbar_,
-      is_inline_direction_triggers_scrollbar_,
       static_cast<NGFragmentationType>(fragmentation_type_),
       separate_leading_fragmentainer_margins_, is_new_fc_, is_anonymous_,
       use_first_line_style_, adjoining_floats_, margin_strut, bfc_offset,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
index 34f86e0c..a612b9ad 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
@@ -49,11 +49,6 @@
 
   NGConstraintSpaceBuilder& SetIsShrinkToFit(bool shrink_to_fit);
 
-  NGConstraintSpaceBuilder& SetIsInlineDirectionTriggersScrollbar(
-      bool is_inline_direction_triggers_scrollbar);
-  NGConstraintSpaceBuilder& SetIsBlockDirectionTriggersScrollbar(
-      bool is_block_direction_triggers_scrollbar);
-
   NGConstraintSpaceBuilder& SetFragmentationType(NGFragmentationType);
 
   NGConstraintSpaceBuilder& SetSeparateLeadingFragmentainerMargins(bool val) {
@@ -109,8 +104,6 @@
   unsigned is_fixed_size_block_ : 1;
   unsigned fixed_size_block_is_definite_ : 1;
   unsigned is_shrink_to_fit_ : 1;
-  unsigned is_inline_direction_triggers_scrollbar_ : 1;
-  unsigned is_block_direction_triggers_scrollbar_ : 1;
   unsigned fragmentation_type_ : 2;
   unsigned separate_leading_fragmentainer_margins_ : 1;
   unsigned is_new_fc_ : 1;
diff --git a/third_party/blink/renderer/core/loader/document_threadable_loader.cc b/third_party/blink/renderer/core/loader/document_threadable_loader.cc
index b487c587..8410172 100644
--- a/third_party/blink/renderer/core/loader/document_threadable_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_threadable_loader.cc
@@ -613,8 +613,9 @@
   if (!actual_request_.IsNull()) {
     ReportResponseReceived(resource->Identifier(), redirect_response);
 
-    HandlePreflightFailure(original_url,
-                           "Response for preflight is invalid (redirect)");
+    HandlePreflightFailure(
+        original_url, CORS::GetErrorString(
+                          CORS::ErrorParameter::CreateForDisallowedRedirect()));
 
     return false;
   }
diff --git a/third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h b/third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h
index 616f624..117d920 100644
--- a/third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h
+++ b/third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h
@@ -31,19 +31,34 @@
       : old_paint_info_(paint_info) {
     DCHECK(fragment.GetLayoutObject());
     const LayoutBox& box = ToLayoutBox(*fragment.GetLayoutObject());
-    if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled() ||
-        !AdjustPaintOffset(box)) {
-      if (!box.HasFlippedBlocksWritingMode()) {
-        adjusted_paint_offset_ =
-            paint_offset + fragment.Offset().ToLayoutPoint();
-      } else {
-        // fragment.Offset() is in physical coordinate, not a flipped physical
-        // coordinate, but BlockPainter::PaintChild() has already incorporated
-        // flipping and assume child painters accumulate flipped offset.
-        // NGBlockNode::CopyFragmentDataToLayoutBox() already computed flipped
-        // fragment.Offset() and stored to LayoutBox, so use it.
-        adjusted_paint_offset_ = paint_offset + box.Location();
-      }
+    if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
+        AdjustPaintOffset(box))
+      return;
+    // This code is poorly understood, this is teams current understanding.
+    //
+    // adjusted_paint_offset should be the flipped block physical frament
+    // offset from Layer() (flipped if flippedBlock, physical otherwise)
+    if (UNLIKELY(box.HasFlippedBlocksWritingMode() ||
+                 box.HasSelfPaintingLayer())) {
+      // Two separate problems result in thesame solution:
+      // A) box.HasSelfPaintingLayer()
+      //   There is no containing block here, we are painting from origin.
+      //   paint_offset is 0,0
+      //   box.Location is offset from Layer()
+      //   => adjusted__paint_offset = box offset from Layer()
+      // C) box.HasFlippedBlocksWritingMode()
+      //   paint_offset is containing box offset from Layer() in flipped blocks
+      //   box.Location is box offset from containing box in flipped blocks
+      //   => adjusted_paint_offset = box offset from Layer()
+      //
+      // fragment.Offset() is in physical coordinate, not a flipped physical
+      // coordinate, but BlockPainter::PaintChild() has already incorporated
+      // flipping and assume child painters accumulate flipped offset.
+      // NGBlockNode::CopyFragmentDataToLayoutBox() already computed flipped
+      // fragment.Offset() and stored to LayoutBox, so use it.
+      adjusted_paint_offset_ = paint_offset + box.Location();
+    } else {
+      adjusted_paint_offset_ = paint_offset + fragment.Offset().ToLayoutPoint();
     }
   }
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
index 18b3559..0ace6d2 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
@@ -42,15 +42,6 @@
   return true;
 }
 
-// Copied from Font.cpp
-inline FloatRect PixelSnappedSelectionRect(FloatRect rect) {
-  // Using roundf() rather than ceilf() for the right edge as a compromise to
-  // ensure correct caret positioning.
-  float rounded_x = roundf(rect.X());
-  return FloatRect(rounded_x, rect.Y(), roundf(rect.MaxX() - rounded_x),
-                   rect.Height());
-}
-
 Color SelectionBackgroundColor(const Document& document,
                                const ComputedStyle& style,
                                const NGPhysicalTextFragment& text_fragment,
@@ -93,20 +84,11 @@
     return;
 
   GraphicsContextStateSaver state_saver(context);
-
-  DCHECK_LE(text_fragment.StartOffset(), selection_status.start);
-  DCHECK_LE(text_fragment.StartOffset(), selection_status.end);
-  DCHECK_GE(text_fragment.EndOffset(), selection_status.start);
-  DCHECK_GE(text_fragment.EndOffset(), selection_status.end);
-  const ShapeResult* shape_result = text_fragment.TextShapeResult();
-  DCHECK(shape_result);
-  const CharacterRange& range = shape_result->GetCharacterRange(
-      selection_status.start - text_fragment.StartOffset(),
-      selection_status.end - text_fragment.StartOffset());
-  const FloatRect& selection_rect = PixelSnappedSelectionRect(
-      FloatRect(box_rect.Location().X() + range.start, box_rect.Location().Y(),
-                range.Width(), box_rect.Height().ToFloat()));
-  context.FillRect(selection_rect, color);
+  const NGPhysicalOffsetRect& ng_rect =
+      text_fragment.LocalRect(selection_status.start, selection_status.end);
+  LayoutRect selection_rect = ng_rect.ToLayoutRect();
+  selection_rect.MoveBy(box_rect.Location());
+  context.FillRect(FloatRect(selection_rect), color);
 }
 
 // This is copied from InlineTextBoxPainter::PaintSelection() but lacks of
diff --git a/third_party/blink/renderer/core/svg/properties/svg_animated_property.h b/third_party/blink/renderer/core/svg/properties/svg_animated_property.h
index 6e75b24..48c579f0a 100644
--- a/third_party/blink/renderer/core/svg/properties/svg_animated_property.h
+++ b/third_party/blink/renderer/core/svg/properties/svg_animated_property.h
@@ -7,7 +7,7 @@
  *
  *     * Redistributions of source code must retain the above copyright
  * notice, this list of conditions and the following disclaimer.
-G*     * Redistributions in binary form must reproduce the above
+ *     * Redistributions in binary form must reproduce the above
  * copyright notice, this list of conditions and the following disclaimer
  * in the documentation and/or other materials provided with the
  * distribution.
@@ -76,9 +76,11 @@
 
   bool IsSpecified() const;
 
-  void Trace(blink::Visitor* visitor) override {}
+  void Trace(blink::Visitor* visitor) override {
+    visitor->Trace(context_element_);
+  }
   virtual void TraceWrappers(ScriptWrappableVisitor* visitor) const {
-    visitor->TraceWrappersWithManualWriteBarrier(context_element_.Get());
+    visitor->TraceWrappers(context_element_);
   }
 
  protected:
@@ -96,12 +98,7 @@
 
   const unsigned type_ : 5;
   const unsigned css_property_id_ : kCssPropertyBits;
-
-  // This raw pointer is safe since the SVG element is guaranteed to be kept
-  // alive by a V8 wrapper.
-  // See http://crbug.com/528275 for the detail.
-  UntracedMember<SVGElement> context_element_;
-
+  TraceWrapperMember<SVGElement> context_element_;
   const QualifiedName& attribute_name_;
   DISALLOW_COPY_AND_ASSIGN(SVGAnimatedPropertyBase);
 };
diff --git a/third_party/blink/renderer/core/svg/properties/svg_property_tear_off.h b/third_party/blink/renderer/core/svg/properties/svg_property_tear_off.h
index 3421c65..ac72e94 100644
--- a/third_party/blink/renderer/core/svg/properties/svg_property_tear_off.h
+++ b/third_party/blink/renderer/core/svg/properties/svg_property_tear_off.h
@@ -72,8 +72,13 @@
     attribute_name_ = attribute_name;
   }
 
+  void Trace(blink::Visitor* visitor) override {
+    visitor->Trace(context_element_);
+    ScriptWrappable::Trace(visitor);
+  }
+
   void TraceWrappers(ScriptWrappableVisitor* visitor) const override {
-    visitor->TraceWrappersWithManualWriteBarrier(context_element_.Get());
+    visitor->TraceWrappers(context_element_);
     ScriptWrappable::TraceWrappers(visitor);
   }
 
@@ -88,10 +93,7 @@
         attribute_name_(attribute_name) {}
 
  private:
-  // This raw pointer is safe since the SVG element is guaranteed to be kept
-  // alive by a V8 wrapper.
-  // See http://crbug.com/528275 for the detail.
-  UntracedMember<SVGElement> context_element_;
+  TraceWrapperMember<SVGElement> context_element_;
 
   PropertyIsAnimValType property_is_anim_val_;
   QualifiedName attribute_name_;
diff --git a/third_party/blink/renderer/core/svg/svg_animated_enumeration.h b/third_party/blink/renderer/core/svg/svg_animated_enumeration.h
index a4ba854..34d845a 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_enumeration.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_enumeration.h
@@ -70,10 +70,6 @@
         SVGAnimatedEnumerationBase::CurrentValue());
   }
 
-  void TraceWrappers(ScriptWrappableVisitor* visitor) const override {
-    SVGAnimatedEnumerationBase::TraceWrappers(visitor);
-  }
-
  protected:
   SVGAnimatedEnumeration(SVGElement* context_element,
                          const QualifiedName& attribute_name,
diff --git a/third_party/blink/renderer/core/workers/parent_execution_context_task_runners.cc b/third_party/blink/renderer/core/workers/parent_execution_context_task_runners.cc
index e2a1b5b..249ebf2 100644
--- a/third_party/blink/renderer/core/workers/parent_execution_context_task_runners.cc
+++ b/third_party/blink/renderer/core/workers/parent_execution_context_task_runners.cc
@@ -27,10 +27,10 @@
     ExecutionContext* context)
     : ContextLifecycleObserver(context) {
   // For now we only support very limited task types.
-  for (auto type :
-       {TaskType::kInternalDefault, TaskType::kInternalLoading,
-        TaskType::kNetworking, TaskType::kPostedMessage, TaskType::kUnthrottled,
-        TaskType::kInternalTest, TaskType::kInternalInspector}) {
+  for (auto type : {TaskType::kInternalDefault, TaskType::kInternalLoading,
+                    TaskType::kNetworking, TaskType::kPostedMessage,
+                    TaskType::kUnthrottled, TaskType::kInternalTest,
+                    TaskType::kInternalInspector, TaskType::kInternalWorker}) {
     auto task_runner =
         context ? context->GetTaskRunner(type)
                 : Platform::Current()->CurrentThread()->GetTaskRunner();
diff --git a/third_party/blink/renderer/core/workers/worker_event_queue.cc b/third_party/blink/renderer/core/workers/worker_event_queue.cc
index 2671084..a9dfe08 100644
--- a/third_party/blink/renderer/core/workers/worker_event_queue.cc
+++ b/third_party/blink/renderer/core/workers/worker_event_queue.cc
@@ -65,7 +65,7 @@
   // database concurrently. See also comments in the ctor of
   // DOMWindowEventQueueTimer.
   // TODO(nhiroki): Callers of enqueueEvent() should specify the task type.
-  global_scope_->GetTaskRunner(TaskType::kUnthrottled)
+  global_scope_->GetTaskRunner(TaskType::kInternalWorker)
       ->PostTask(from_here,
                  WTF::Bind(&WorkerEventQueue::DispatchEvent,
                            WrapPersistent(this), WrapWeakPersistent(event)));
diff --git a/third_party/blink/renderer/core/workers/worker_thread.cc b/third_party/blink/renderer/core/workers/worker_thread.cc
index 12a984d..86be8724 100644
--- a/third_party/blink/renderer/core/workers/worker_thread.cc
+++ b/third_party/blink/renderer/core/workers/worker_thread.cc
@@ -137,7 +137,7 @@
     const v8_inspector::V8StackTraceId& stack_id) {
   DCHECK_CALLED_ON_VALID_THREAD(parent_thread_checker_);
   PostCrossThreadTask(
-      *GetTaskRunner(TaskType::kUnthrottled), FROM_HERE,
+      *GetTaskRunner(TaskType::kInternalWorker), FROM_HERE,
       CrossThreadBind(&WorkerThread::EvaluateClassicScriptOnWorkerThread,
                       CrossThreadUnretained(this), script_url, source_code,
                       WTF::Passed(std::move(cached_meta_data)), stack_id));
@@ -148,7 +148,7 @@
     network::mojom::FetchCredentialsMode credentials_mode) {
   DCHECK_CALLED_ON_VALID_THREAD(parent_thread_checker_);
   PostCrossThreadTask(
-      *GetTaskRunner(TaskType::kUnthrottled), FROM_HERE,
+      *GetTaskRunner(TaskType::kInternalWorker), FROM_HERE,
       CrossThreadBind(&WorkerThread::ImportModuleScriptOnWorkerThread,
                       CrossThreadUnretained(this), script_url,
                       credentials_mode));
diff --git a/third_party/blink/renderer/core/workers/worklet_options.idl b/third_party/blink/renderer/core/workers/worklet_options.idl
index bc4d7ca..87aa0d9 100644
--- a/third_party/blink/renderer/core/workers/worklet_options.idl
+++ b/third_party/blink/renderer/core/workers/worklet_options.idl
@@ -4,5 +4,5 @@
 
 // https://drafts.css-houdini.org/worklets/#dictdef-workletoptions
 dictionary WorkletOptions {
-    RequestCredentials credentials = "omit";
+    RequestCredentials credentials = "same-origin";
 };
diff --git a/third_party/blink/renderer/devtools/front_end/common/ResourceType.js b/third_party/blink/renderer/devtools/front_end/common/ResourceType.js
index 63e006a..17beaef 100644
--- a/third_party/blink/renderer/devtools/front_end/common/ResourceType.js
+++ b/third_party/blink/renderer/devtools/front_end/common/ResourceType.js
@@ -232,6 +232,7 @@
   SourceMapStyleSheet:
       new Common.ResourceType('sm-stylesheet', 'Stylesheet', Common.resourceCategories.Stylesheet, true),
   Manifest: new Common.ResourceType('manifest', 'Manifest', Common.resourceCategories.Manifest, true),
+  SignedExchange: new Common.ResourceType('signed-exchange', 'SignedExchange', Common.resourceCategories.Other, false),
 };
 
 
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/NetworkManager.js b/third_party/blink/renderer/devtools/front_end/sdk/NetworkManager.js
index 7cec14d..e29d631 100644
--- a/third_party/blink/renderer/devtools/front_end/sdk/NetworkManager.js
+++ b/third_party/blink/renderer/devtools/front_end/sdk/NetworkManager.js
@@ -426,8 +426,7 @@
         return;
     }
     networkRequest.setSignedExchangeInfo(info);
-    // TODO(crbug/830505): Introduce a new resource type for Signed Exchange.
-    networkRequest.setResourceType(Common.resourceTypes.Other);
+    networkRequest.setResourceType(Common.resourceTypes.SignedExchange);
 
     this._updateNetworkRequestWithResponse(networkRequest, info.outerResponse);
     this._updateNetworkRequest(networkRequest);
diff --git a/third_party/blink/renderer/modules/notifications/notification.cc b/third_party/blink/renderer/modules/notifications/notification.cc
index 82895d1..52338c5a 100644
--- a/third_party/blink/renderer/modules/notifications/notification.cc
+++ b/third_party/blink/renderer/modules/notifications/notification.cc
@@ -33,10 +33,7 @@
 #include "base/unguessable_token.h"
 #include "third_party/blink/public/platform/modules/notifications/web_notification_action.h"
 #include "third_party/blink/public/platform/modules/notifications/web_notification_constants.h"
-#include "third_party/blink/public/platform/modules/notifications/web_notification_manager.h"
-#include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/public/platform/web_security_origin.h"
 #include "third_party/blink/renderer/bindings/core/v8/exception_state.h"
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value_factory.h"
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
@@ -63,13 +60,6 @@
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
-namespace {
-
-WebNotificationManager* GetWebNotificationManager() {
-  return Platform::Current()->GetWebNotificationManager();
-}
-
-}  // namespace
 
 Notification* Notification::Create(ExecutionContext* context,
                                    const String& title,
@@ -167,7 +157,6 @@
       state_(State::kLoading),
       data_(data),
       listener_binding_(this) {
-  DCHECK(GetWebNotificationManager());
 }
 
 Notification::~Notification() = default;
@@ -231,17 +220,8 @@
 
   state_ = State::kClosed;
 
-  if (RuntimeEnabledFeatures::NotificationsWithMojoEnabled()) {
-    NotificationManager::From(GetExecutionContext())
-        ->ClosePersistentNotification(notification_id_);
-    return;
-  }
-
-  const SecurityOrigin* origin = GetExecutionContext()->GetSecurityOrigin();
-  DCHECK(origin);
-
-  GetWebNotificationManager()->ClosePersistent(WebSecurityOrigin(origin),
-                                               data_.tag, notification_id_);
+  NotificationManager::From(GetExecutionContext())
+      ->ClosePersistentNotification(notification_id_);
 }
 
 void Notification::OnShow() {
diff --git a/third_party/blink/renderer/modules/notifications/notification_manager.h b/third_party/blink/renderer/modules/notifications/notification_manager.h
index 7237bc0b..412a6c50 100644
--- a/third_party/blink/renderer/modules/notifications/notification_manager.h
+++ b/third_party/blink/renderer/modules/notifications/notification_manager.h
@@ -6,7 +6,6 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_NOTIFICATIONS_NOTIFICATION_MANAGER_H_
 
 #include "third_party/blink/public/platform/modules/notifications/notification_service.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/notifications/web_notification_manager.h"
 #include "third_party/blink/public/platform/modules/permissions/permission.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_notification_permission_callback.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -18,6 +17,7 @@
 class ScriptPromise;
 class ScriptPromiseResolver;
 class ScriptState;
+class WebServiceWorkerRegistration;
 struct WebNotificationData;
 
 // The notification manager, unique to the execution context, is responsible for
diff --git a/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.cc b/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.cc
index 7965093..4fc5040 100644
--- a/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.cc
+++ b/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.cc
@@ -9,11 +9,9 @@
 #include "third_party/blink/public/platform/modules/notifications/web_notification_data.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
-#include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h"
 #include "third_party/blink/renderer/bindings/core/v8/exception_state.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/modules/notifications/get_notification_options.h"
-#include "third_party/blink/renderer/modules/notifications/notification.h"
 #include "third_party/blink/renderer/modules/notifications/notification_data.h"
 #include "third_party/blink/renderer/modules/notifications/notification_manager.h"
 #include "third_party/blink/renderer/modules/notifications/notification_options.h"
@@ -25,32 +23,6 @@
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 
 namespace blink {
-namespace {
-
-// Allows using a CallbackPromiseAdapter with a WebVector to resolve the
-// getNotifications() promise with a HeapVector owning Notifications.
-class NotificationArray {
- public:
-  using WebType = const WebVector<WebPersistentNotificationInfo>&;
-
-  static HeapVector<Member<Notification>> Take(
-      ScriptPromiseResolver* resolver,
-      const WebVector<WebPersistentNotificationInfo>& notification_infos) {
-    HeapVector<Member<Notification>> notifications;
-    for (const WebPersistentNotificationInfo& notification_info :
-         notification_infos)
-      notifications.push_back(Notification::Create(
-          resolver->GetExecutionContext(), notification_info.notification_id,
-          notification_info.data, true /* showing */));
-
-    return notifications;
-  }
-
- private:
-  NotificationArray() = delete;
-};
-
-}  // namespace
 
 ServiceWorkerRegistrationNotifications::ServiceWorkerRegistrationNotifications(
     ExecutionContext* context,
@@ -115,23 +87,10 @@
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
   ScriptPromise promise = resolver->Promise();
 
-  if (RuntimeEnabledFeatures::NotificationsWithMojoEnabled()) {
-    ExecutionContext* execution_context = ExecutionContext::From(script_state);
-    NotificationManager::From(execution_context)
-        ->GetNotifications(registration.WebRegistration(), options.tag(),
-                           WrapPersistent(resolver));
-  } else {
-    auto callbacks =
-        std::make_unique<CallbackPromiseAdapter<NotificationArray, void>>(
-            resolver);
-
-    WebNotificationManager* notification_manager =
-        Platform::Current()->GetWebNotificationManager();
-    DCHECK(notification_manager);
-
-    notification_manager->GetNotifications(
-        options.tag(), registration.WebRegistration(), std::move(callbacks));
-  }
+  ExecutionContext* execution_context = ExecutionContext::From(script_state);
+  NotificationManager::From(execution_context)
+      ->GetNotifications(registration.WebRegistration(), options.tag(),
+                         WrapPersistent(resolver));
   return promise;
 }
 
@@ -186,23 +145,10 @@
     NotificationResourcesLoader* loader) {
   DCHECK(loaders_.Contains(loader));
 
-  if (RuntimeEnabledFeatures::NotificationsWithMojoEnabled()) {
-    NotificationManager::From(GetExecutionContext())
-        ->DisplayPersistentNotification(registration_->WebRegistration(), data,
-                                        loader->GetResources(),
-                                        WrapPersistent(resolver));
-  } else {
-    WebNotificationManager* notification_manager =
-        Platform::Current()->GetWebNotificationManager();
-    DCHECK(notification_manager);
-
-    std::unique_ptr<WebNotificationShowCallbacks> callbacks =
-        std::make_unique<CallbackPromiseAdapter<void, void>>(resolver);
-
-    notification_manager->ShowPersistent(
-        WebSecurityOrigin(origin.get()), data, loader->GetResources(),
-        registration_->WebRegistration(), std::move(callbacks));
-  }
+  NotificationManager::From(GetExecutionContext())
+      ->DisplayPersistentNotification(registration_->WebRegistration(), data,
+                                      loader->GetResources(),
+                                      WrapPersistent(resolver));
   loaders_.erase(loader);
 }
 
diff --git a/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h b/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h
index a27370e..995219c 100644
--- a/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h
+++ b/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h
@@ -7,12 +7,10 @@
 
 #include <memory>
 #include "base/memory/scoped_refptr.h"
-#include "third_party/blink/public/platform/modules/notifications/web_notification_manager.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
 #include "third_party/blink/renderer/platform/wtf/noncopyable.h"
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc
index 83a3103..71ffe00f 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -200,6 +200,15 @@
     exception_state.ThrowRangeError(error_message);
     return;
   }
+
+  // TODO(zino): The `currencySystem` member is deprecated in spec side.
+  // We want to count when the currency code is not well-formed.
+  // Please see http://crbug.com/839402
+  if (ScriptRegexp("^[A-Z]{3}$", kTextCaseUnicodeInsensitive)
+          .Match(item.amount().currency()) != 0) {
+    UseCounter::Count(&execution_context,
+                      WebFeature::kPaymentRequestInvalidCurrencyCode);
+  }
 }
 
 void ValidateAndConvertDisplayItems(const HeapVector<PaymentItem>& input,
diff --git a/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_proxy.cc
index 02a061b..13289a2 100644
--- a/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_proxy.cc
+++ b/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope_proxy.cc
@@ -563,7 +563,7 @@
   DCHECK(embedded_worker_);
   WaitableEvent waitable_event;
   PostCrossThreadTask(
-      *parent_execution_context_task_runners_->Get(TaskType::kUnthrottled),
+      *parent_execution_context_task_runners_->Get(TaskType::kInternalWorker),
       FROM_HERE,
       CrossThreadBind(&SetContentSecurityPolicyAndReferrerPolicyOnMainThread,
                       CrossThreadUnretained(embedded_worker_),
diff --git a/third_party/blink/renderer/modules/shapedetection/face_detector.cc b/third_party/blink/renderer/modules/shapedetection/face_detector.cc
index 0540d44..a56de521 100644
--- a/third_party/blink/renderer/modules/shapedetection/face_detector.cc
+++ b/third_party/blink/renderer/modules/shapedetection/face_detector.cc
@@ -81,11 +81,16 @@
 
       Landmark web_landmark;
       web_landmark.setLocations(locations);
+      // TODO(junwei.fu): Consider using TypeConverter to convert the type of
+      // landmark from Mojo to IDL (https://crbug.com/841649).
       if (landmark->type == shape_detection::mojom::blink::LandmarkType::EYE) {
         web_landmark.setType("eye");
       } else if (landmark->type ==
                  shape_detection::mojom::blink::LandmarkType::MOUTH) {
         web_landmark.setType("mouth");
+      } else if (landmark->type ==
+                 shape_detection::mojom::blink::LandmarkType::NOSE) {
+        web_landmark.setType("nose");
       }
       landmarks.push_back(web_landmark);
     }
diff --git a/third_party/blink/renderer/modules/shapedetection/landmark.idl b/third_party/blink/renderer/modules/shapedetection/landmark.idl
index 4a5df643..f89de57 100644
--- a/third_party/blink/renderer/modules/shapedetection/landmark.idl
+++ b/third_party/blink/renderer/modules/shapedetection/landmark.idl
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // https://wicg.github.io/shape-detection-api/#enumdef-landmarktype
-enum LandmarkType { "mouth", "eye" };
+enum LandmarkType { "mouth", "eye", "nose" };
 
 // https://wicg.github.io/shape-detection-api/#dictdef-landmark
 dictionary Landmark {
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc
index 8ab8deef..31babc13 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc
@@ -158,10 +158,4 @@
   WebGL2RenderingContextBase::Trace(visitor);
 }
 
-void WebGL2RenderingContext::TraceWrappers(
-    ScriptWrappableVisitor* visitor) const {
-  // Extensions are managed by WebGL2RenderingContextBase.
-  WebGL2RenderingContextBase::TraceWrappers(visitor);
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h
index 1b48be4..35d805e 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.h
@@ -49,8 +49,6 @@
 
   void Trace(blink::Visitor*) override;
 
-  void TraceWrappers(ScriptWrappableVisitor*) const override;
-
  protected:
   WebGL2RenderingContext(
       CanvasRenderingContextHost*,
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc
index a673105..f4455da 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc
@@ -220,10 +220,4 @@
   WebGLRenderingContextBase::Trace(visitor);
 }
 
-void WebGLRenderingContext::TraceWrappers(
-    ScriptWrappableVisitor* visitor) const {
-  // Extensions are managed base WebGLRenderingContextBase.
-  WebGLRenderingContextBase::TraceWrappers(visitor);
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h
index bd444bb2..2521d87 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context.h
@@ -83,8 +83,6 @@
 
   void Trace(blink::Visitor*) override;
 
-  void TraceWrappers(ScriptWrappableVisitor*) const override;
-
  private:
   WebGLRenderingContext(CanvasRenderingContextHost*,
                         std::unique_ptr<WebGraphicsContext3DProvider>,
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index ed1304d..11fddf5a 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -204,10 +204,6 @@
   RuntimeEnabledFeatures::SetNotificationsEnabled(enable);
 }
 
-void WebRuntimeFeatures::EnableNotificationsWithMojo(bool enable) {
-  RuntimeEnabledFeatures::SetNotificationsWithMojoEnabled(enable);
-}
-
 void WebRuntimeFeatures::EnableNavigatorContentUtils(bool enable) {
   RuntimeEnabledFeatures::SetNavigatorContentUtilsEnabled(enable);
 }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
index e1a5a8d2..8c80c1d3 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
@@ -28,6 +28,15 @@
   DCHECK(!sync_token_for_release_.HasData());
 }
 
+bool CanvasResource::IsBitmap() {
+  return false;
+}
+
+scoped_refptr<StaticBitmapImage> CanvasResource::Bitmap() {
+  NOTREACHED();
+  return nullptr;
+}
+
 gpu::gles2::GLES2Interface* CanvasResource::ContextGL() const {
   if (!ContextProviderWrapper())
     return nullptr;
@@ -126,6 +135,27 @@
   return image_->IsValid();
 }
 
+bool CanvasResourceBitmap::IsAccelerated() const {
+  return image_->IsTextureBacked();
+}
+
+scoped_refptr<CanvasResource> CanvasResourceBitmap::MakeAccelerated(
+    base::WeakPtr<WebGraphicsContext3DProviderWrapper>
+        context_provider_wrapper) {
+  if (IsAccelerated() || !context_provider_wrapper)
+    return base::WrapRefCounted(this);
+  scoped_refptr<StaticBitmapImage> accelerated_image =
+      image_->MakeAccelerated(context_provider_wrapper);
+  // passing nullptr for the resource provider argument creates an orphan
+  // CanvasResource, which implies that it internal resources will not be
+  // recycled.
+  scoped_refptr<CanvasResource> accelerated_resource =
+      Create(accelerated_image, nullptr, filterQuality());
+  if (!accelerated_resource)
+    return base::WrapRefCounted(this);
+  return accelerated_resource;
+}
+
 void CanvasResourceBitmap::TearDown() {
   WaitSyncTokenBeforeRelease();
   // We must not disassociate the mailbox from the texture object here because
@@ -144,6 +174,14 @@
   return GL_TEXTURE_2D;
 }
 
+bool CanvasResourceBitmap::IsBitmap() {
+  return true;
+}
+
+scoped_refptr<StaticBitmapImage> CanvasResourceBitmap::Bitmap() {
+  return image_;
+}
+
 const gpu::Mailbox& CanvasResourceBitmap::GetOrCreateGpuMailbox() {
   DCHECK(image_);  // Calling code should check IsValid() before calling this.
   image_->EnsureMailbox(kUnverifiedSyncToken, GLFilter());
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.h b/third_party/blink/renderer/platform/graphics/canvas_resource.h
index b6456f1..58d7340 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource.h
@@ -39,6 +39,7 @@
   virtual ~CanvasResource();
   virtual void Abandon() = 0;
   virtual bool IsRecycleable() const = 0;
+  virtual bool IsAccelerated() const = 0;
   virtual bool IsValid() const = 0;
   virtual IntSize Size() const = 0;
   virtual const gpu::Mailbox& GetOrCreateGpuMailbox() = 0;
@@ -47,6 +48,10 @@
       viz::TransferableResource* out_resource,
       std::unique_ptr<viz::SingleReleaseCallback>* out_callback);
   void SetSyncTokenForRelease(const gpu::SyncToken&);
+  virtual scoped_refptr<CanvasResource> MakeAccelerated(
+      base::WeakPtr<WebGraphicsContext3DProviderWrapper>) = 0;
+  virtual bool IsBitmap();
+  virtual scoped_refptr<StaticBitmapImage> Bitmap();
   void WaitSyncTokenBeforeRelease();
   virtual void CopyFromTexture(GLuint source_texture,
                                GLenum format,
@@ -67,6 +72,7 @@
   void PrepareTransferableResourceCommon(
       viz::TransferableResource* out_resource,
       std::unique_ptr<viz::SingleReleaseCallback>* out_callback);
+  SkFilterQuality filterQuality() const { return filter_quality_; }
 
  private:
   // Sync token that was provided when resource was released
@@ -87,9 +93,14 @@
   // Not recyclable: Skia handles texture recycling internally and bitmaps are
   // cheap to allocate.
   bool IsRecycleable() const final { return false; }
+  bool IsAccelerated() const final;
   bool IsValid() const final;
   void Abandon() final { TearDown(); }
   IntSize Size() const final;
+  bool IsBitmap() final;
+  scoped_refptr<StaticBitmapImage> Bitmap() final;
+  scoped_refptr<CanvasResource> MakeAccelerated(
+      base::WeakPtr<WebGraphicsContext3DProviderWrapper>) final;
 
  private:
   void TearDown();
@@ -119,9 +130,14 @@
       SkFilterQuality);
   ~CanvasResourceGpuMemoryBuffer() override;
   bool IsRecycleable() const final { return IsValid(); }
+  bool IsAccelerated() const final { return true; }
   bool IsValid() const override {
     return context_provider_wrapper_ && image_id_;
   }
+  scoped_refptr<CanvasResource> MakeAccelerated(
+      base::WeakPtr<WebGraphicsContext3DProviderWrapper>) final {
+    return base::WrapRefCounted(this);
+  };
   void Abandon() final { TearDown(); }
   IntSize Size() const final;
 
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_test.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_test.cc
index ed78ed60..90767cf 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_test.cc
@@ -194,4 +194,58 @@
   testing::Mock::VerifyAndClearExpectations(&gl_);
 }
 
+TEST_F(CanvasResourceTest, MakeAcceleratedFromAcceleratedResourceIsNoOp) {
+  ScopedTestingPlatformSupport<FakeCanvasResourcePlatformSupport> platform;
+
+  SkImageInfo image_info =
+      SkImageInfo::MakeN32(10, 10, kPremul_SkAlphaType, nullptr);
+  sk_sp<SkSurface> surface =
+      SkSurface::MakeRenderTarget(GetGrContext(), SkBudgeted::kYes, image_info);
+
+  testing::Mock::VerifyAndClearExpectations(&gl_);
+
+  EXPECT_TRUE(!!context_provider_wrapper_);
+  scoped_refptr<CanvasResource> resource = CanvasResourceBitmap::Create(
+      StaticBitmapImage::Create(surface->makeImageSnapshot(),
+                                context_provider_wrapper_),
+      nullptr, kLow_SkFilterQuality);
+
+  testing::Mock::VerifyAndClearExpectations(&gl_);
+
+  EXPECT_TRUE(resource->IsAccelerated());
+  scoped_refptr<CanvasResource> new_resource =
+      resource->MakeAccelerated(context_provider_wrapper_);
+
+  testing::Mock::VerifyAndClearExpectations(&gl_);
+
+  EXPECT_EQ(new_resource.get(), resource.get());
+  EXPECT_TRUE(new_resource->IsAccelerated());
+}
+
+TEST_F(CanvasResourceTest, MakeAcceleratedFromRasterResource) {
+  ScopedTestingPlatformSupport<FakeCanvasResourcePlatformSupport> platform;
+
+  SkImageInfo image_info =
+      SkImageInfo::MakeN32(10, 10, kPremul_SkAlphaType, nullptr);
+  sk_sp<SkSurface> surface = SkSurface::MakeRaster(image_info);
+
+  EXPECT_TRUE(!!context_provider_wrapper_);
+  scoped_refptr<CanvasResource> resource = CanvasResourceBitmap::Create(
+      StaticBitmapImage::Create(surface->makeImageSnapshot(),
+                                context_provider_wrapper_),
+      nullptr, kLow_SkFilterQuality);
+
+  testing::Mock::VerifyAndClearExpectations(&gl_);
+
+  EXPECT_FALSE(resource->IsAccelerated());
+  scoped_refptr<CanvasResource> new_resource =
+      resource->MakeAccelerated(context_provider_wrapper_);
+
+  testing::Mock::VerifyAndClearExpectations(&gl_);
+
+  EXPECT_NE(new_resource.get(), resource.get());
+  EXPECT_FALSE(resource->IsAccelerated());
+  EXPECT_TRUE(new_resource->IsAccelerated());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc b/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc
index be05c48..03a485a 100644
--- a/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc
+++ b/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc
@@ -121,6 +121,14 @@
 }
 
 // static
+ErrorParameter ErrorParameter::CreateForDisallowedRedirect() {
+  return ErrorParameter(
+      network::mojom::CORSError::kPreflightDisallowedRedirect, GetInvalidURL(),
+      GetInvalidURL(), 0, HTTPHeaderMap(), *SecurityOrigin::CreateUnique(),
+      WebURLRequest::kRequestContextUnspecified, String(), false);
+}
+
+// static
 ErrorParameter ErrorParameter::CreateForExternalPreflightCheck(
     const network::mojom::CORSError error,
     const HTTPHeaderMap& response_header_map) {
@@ -335,6 +343,8 @@
                : ""));
     case network::mojom::CORSError::kPreflightInvalidStatus:
       return String("Response for preflight does not have HTTP ok status.");
+    case network::mojom::CORSError::kPreflightDisallowedRedirect:
+      return String("Response for preflight is invalid (redirect)");
     case network::mojom::CORSError::kPreflightMissingAllowExternal:
       return String(
           "No 'Access-Control-Allow-External' header was present in the "
diff --git a/third_party/blink/renderer/platform/loader/cors/cors_error_string.h b/third_party/blink/renderer/platform/loader/cors/cors_error_string.h
index 8adfbf61..35dab0a9 100644
--- a/third_party/blink/renderer/platform/loader/cors/cors_error_string.h
+++ b/third_party/blink/renderer/platform/loader/cors/cors_error_string.h
@@ -55,6 +55,9 @@
   // CORS::CheckPreflight() returns.
   static ErrorParameter CreateForPreflightStatusCheck(int response_status_code);
 
+  // Creates an ErrorParameter for kPreflightDisallowedRedirect.
+  static ErrorParameter CreateForDisallowedRedirect();
+
   // Creates an ErrorParameter for an error that CORS::CheckExternalPreflight()
   // returns.
   static ErrorParameter CreateForExternalPreflightCheck(
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index f1af7dd6..daa560b7 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -845,9 +845,6 @@
       status: "stable",
     },
     {
-      name: "NotificationsWithMojo",
-    },
-    {
       name: "NullableDocumentDomain",
       status: "experimental",
     },
diff --git a/third_party/blink/renderer/platform/scheduler/child/worker_scheduler.cc b/third_party/blink/renderer/platform/scheduler/child/worker_scheduler.cc
index 7ffb883b..2e2f9fa 100644
--- a/third_party/blink/renderer/platform/scheduler/child/worker_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/child/worker_scheduler.cc
@@ -71,6 +71,7 @@
     case TaskType::kInternalUserInteraction:
     case TaskType::kInternalInspector:
     case TaskType::kInternalAnimation:
+    case TaskType::kInternalWorker:
       // UnthrottledTaskRunner is generally discouraged in future.
       // TODO(nhiroki): Identify which tasks can be throttled / suspendable and
       // move them into other task runners. See also comments in
diff --git a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc
index a6ee224..b0358ea 100644
--- a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc
@@ -8,8 +8,8 @@
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "components/viz/test/ordered_simple_task_runner.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/scheduler/base/lazy_now.h"
@@ -50,27 +50,29 @@
 class SchedulerHelperTest : public testing::Test {
  public:
   SchedulerHelperTest()
-      : mock_task_runner_(new cc::OrderedSimpleTaskRunner(&clock_, false)) {
+      : task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
+            base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED) {
+    // Null clock triggers some assertions.
+    task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(5));
     std::unique_ptr<TaskQueueManagerForTest> task_queue_manager =
-        TaskQueueManagerForTest::Create(nullptr, mock_task_runner_, &clock_);
+        TaskQueueManagerForTest::Create(nullptr,
+                                        base::ThreadTaskRunnerHandle::Get(),
+                                        task_environment_.GetMockTickClock());
     task_queue_manager_ = task_queue_manager.get();
     scheduler_helper_ = std::make_unique<NonMainThreadSchedulerHelper>(
         std::move(task_queue_manager), nullptr);
     default_task_runner_ = scheduler_helper_->DefaultWorkerTaskQueue();
-    clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
   }
 
   ~SchedulerHelperTest() override = default;
 
   void TearDown() override {
     // Check that all tests stop posting tasks.
-    mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
-    while (mock_task_runner_->RunUntilIdle()) {
-    }
+    task_environment_.FastForwardUntilNoTasksRemain();
+    EXPECT_EQ(0u, task_environment_.GetPendingMainThreadTaskCount());
   }
 
-  void RunUntilIdle() { mock_task_runner_->RunUntilIdle(); }
-
   template <typename E>
   static void CallForEachEnumValue(E first,
                                    E last,
@@ -82,9 +84,7 @@
   }
 
  protected:
-  base::SimpleTestTickClock clock_;
-  scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
-
+  base::test::ScopedTaskEnvironment task_environment_;
   std::unique_ptr<NonMainThreadSchedulerHelper> scheduler_helper_;
   TaskQueueManagerForTest* task_queue_manager_;  // Owned by scheduler_helper.
   scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
@@ -103,7 +103,7 @@
   default_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&AppendToVectorTestTask, &run_order, "D4"));
 
-  RunUntilIdle();
+  task_environment_.RunUntilIdle();
   EXPECT_THAT(run_order,
               testing::ElementsAre(std::string("D1"), std::string("D2"),
                                    std::string("D3"), std::string("D4")));
@@ -116,7 +116,7 @@
       FROM_HERE, base::BindOnce(AppendToVectorReentrantTask,
                                 base::RetainedRef(default_task_runner_),
                                 &run_order, &count, 5));
-  RunUntilIdle();
+  task_environment_.RunUntilIdle();
 
   EXPECT_THAT(run_order, testing::ElementsAre(0, 1, 2, 3, 4));
 }
@@ -137,7 +137,7 @@
   scheduler_helper_->ControlWorkerTaskQueue()->PostTask(
       FROM_HERE, base::BindOnce(&AppendToVectorTestTask, &run_order, "C1"));
   EXPECT_EQ(3U, task_queue_manager_->PendingTasksCount());
-  RunUntilIdle();
+  task_environment_.RunUntilIdle();
   EXPECT_EQ(0U, task_queue_manager_->PendingTasksCount());
 }
 
@@ -160,7 +160,7 @@
 
   EXPECT_CALL(observer, WillProcessTask(_)).Times(1);
   EXPECT_CALL(observer, DidProcessTask(_)).Times(1);
-  RunUntilIdle();
+  task_environment_.RunUntilIdle();
 }
 
 TEST_F(SchedulerHelperTest, ObserversNotNotifiedFor_ControlTaskQueue) {
@@ -172,7 +172,7 @@
 
   EXPECT_CALL(observer, WillProcessTask(_)).Times(0);
   EXPECT_CALL(observer, DidProcessTask(_)).Times(0);
-  RunUntilIdle();
+  task_environment_.RunUntilIdle();
 }
 
 }  // namespace scheduler_helper_unittest
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
index 1f5ee45..930a497d 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -308,6 +308,10 @@
     // The TaskType of Inspector tasks needs to be unpausable because they need
     // to run even on a paused page.
     case TaskType::kInternalInspector:
+    // The TaskType of worker tasks needs to be unpausable (in addition to
+    // unthrottled and undeferred) not to prevent service workers that may
+    // control browser navigation on multiple tabs.
+    case TaskType::kInternalWorker:
       return TaskRunnerImpl::Create(UnpausableTaskQueue(), type);
     case TaskType::kDeprecatedNone:
     case TaskType::kCount:
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index 5efafa0..a0baf8d5 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -180,6 +180,8 @@
       return "InternalInspector";
     case TaskType::kInternalAnimation:
       return "InternalAnimation";
+    case TaskType::kInternalWorker:
+      return "InternalWorker";
     case TaskType::kCount:
       return "Count";
   }
diff --git a/third_party/closure_compiler/build/get_includes.py b/third_party/closure_compiler/build/get_includes.py
deleted file mode 100755
index 6d976db..0000000
--- a/third_party/closure_compiler/build/get_includes.py
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/python
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os.path
-import sys
-
-
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
-import processor
-
-
-def GetIncludes(inputs):
-  includes = set()
-  for f in inputs:
-    includes.update(processor.Processor(f).included_files)
-  return includes
-
-
-if __name__ == "__main__":
-  # TODO(dpapad): Dedup inputs in ninja files, using relative paths with respect
-  # to the out directory.
-  print "\n".join(GetIncludes(sys.argv[1:]))
diff --git a/third_party/closure_compiler/compiled_resources2.gyp b/third_party/closure_compiler/compiled_resources2.gyp
index bb1b6e3c..592e50d 100644
--- a/third_party/closure_compiler/compiled_resources2.gyp
+++ b/third_party/closure_compiler/compiled_resources2.gyp
@@ -23,8 +23,6 @@
         '<(DEPTH)/chrome/browser/resources/chromeos/switch_access/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/chromeos/sys_internals/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/ntp4/compiled_resources2.gyp:*',
-        '<(DEPTH)/chrome/browser/resources/print_preview/compiled_resources2.gyp:*',
-        '<(DEPTH)/chrome/browser/resources/print_preview/new/compiled_resources2.gyp:*',
         '<(DEPTH)/ui/webui/resources/cr_components/compiled_resources2.gyp:*',
         '<(DEPTH)/ui/webui/resources/cr_elements/compiled_resources2.gyp:*',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:*',
diff --git a/third_party/closure_compiler/externs/file_manager_private.js b/third_party/closure_compiler/externs/file_manager_private.js
index 12751a1a..c64d44c 100644
--- a/third_party/closure_compiler/externs/file_manager_private.js
+++ b/third_party/closure_compiler/externs/file_manager_private.js
@@ -730,14 +730,15 @@
 
 /**
  * Returns true if crostini is enabled.
- * @param {function(!boolean)} callback
+ * @param {function(boolean)} callback
  */
 chrome.fileManagerPrivate.isCrostiniEnabled = function(callback) {};
 
 /**
  * Starts and mounts crostini container.
+ * @param {function(boolean)} callback
  */
-chrome.fileManagerPrivate.mountCrostiniContainer = function() {};
+chrome.fileManagerPrivate.mountCrostiniContainer = function(callback) {};
 
 /** @type {!ChromeEvent} */
 chrome.fileManagerPrivate.onMountCompleted;
diff --git a/tools/clang/scripts/run_tool.py b/tools/clang/scripts/run_tool.py
index 52597dd..0a3903c 100755
--- a/tools/clang/scripts/run_tool.py
+++ b/tools/clang/scripts/run_tool.py
@@ -48,6 +48,7 @@
 """
 
 import argparse
+from collections import namedtuple
 import functools
 import json
 import multiprocessing
@@ -55,6 +56,7 @@
 import os.path
 import re
 import subprocess
+import shlex
 import sys
 
 script_dir = os.path.dirname(os.path.realpath(__file__))
@@ -64,6 +66,8 @@
 from clang import compile_db
 
 
+CompDBEntry = namedtuple('CompDBEntry', ['directory', 'filename', 'command'])
+
 def _PruneGitFiles(git_files, paths):
   """Prunes the list of files from git to include only those that are either in
   |paths| or start with one item in |paths|.
@@ -132,14 +136,22 @@
   return files
 
 
-def _GetFilesFromCompileDB(build_directory):
-  """ Gets the list of files mentioned in the compilation database.
+def _GetEntriesFromCompileDB(build_directory, source_filenames):
+  """ Gets the list of files and args mentioned in the compilation database.
 
   Args:
     build_directory: Directory that contains the compile database.
+    source_filenames: If not None, only include entries for the given list of
+      filenames.
   """
-  return [os.path.join(entry['directory'], entry['file'])
-          for entry in compile_db.Read(build_directory)]
+
+  filenames_set = None if source_filenames is None else set(source_filenames)
+  return [
+      CompDBEntry(entry['directory'], entry['file'], entry['command'])
+      for entry in compile_db.Read(build_directory)
+      if filenames_set is None or os.path.realpath(
+          os.path.join(entry['directory'], entry['file'])) in filenames_set
+  ]
 
 
 def _UpdateCompileCommandsIfNeeded(compile_commands, files_list):
@@ -167,7 +179,7 @@
   return compile_db.ProcessCompileDatabaseIfNeeded(filtered_compile_commands)
 
 
-def _ExecuteTool(toolname, tool_args, build_directory, filename):
+def _ExecuteTool(toolname, tool_args, build_directory, compdb_entry):
   """Executes the clang tool.
 
   This is defined outside the class so it can be pickled for the multiprocessing
@@ -177,7 +189,7 @@
     toolname: Name of the clang tool to execute.
     tool_args: Arguments to be passed to the clang tool. Can be None.
     build_directory: Directory that contains the compile database.
-    filename: The file to run the clang tool over.
+    compdb_entry: The file and args to run the clang tool over.
 
   Returns:
     A dictionary that must contain the key "status" and a boolean value
@@ -189,38 +201,59 @@
     Otherwise, the filename and the output from stderr are associated with the
     keys "filename" and "stderr_text" respectively.
   """
-  args = [toolname, '-p', build_directory, filename]
+
+  args = [toolname, compdb_entry.filename]
   if (tool_args):
     args.extend(tool_args)
+
+  args.append('--')
+  args.extend([
+      a for a in shlex.split(compdb_entry.command)
+      # 'command' contains the full command line, including the input
+      # source file itself. We need to filter it out otherwise it's
+      # passed to the tool twice - once directly and once via
+      # the compile args.
+      if a != compdb_entry.filename
+  ])
+
   command = subprocess.Popen(
-      args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+      args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=build_directory)
   stdout_text, stderr_text = command.communicate()
   stderr_text = re.sub(
       r"^warning: .*'linker' input unused \[-Wunused-command-line-argument\]\n",
       "", stderr_text, flags=re.MULTILINE)
+
   if command.returncode != 0:
-    return {'status': False, 'filename': filename, 'stderr_text': stderr_text}
+    return {
+        'status': False,
+        'filename': compdb_entry.filename,
+        'stderr_text': stderr_text,
+    }
   else:
-    return {'status': True, 'filename': filename, 'stdout_text': stdout_text,
-            'stderr_text': stderr_text}
+    return {
+        'status': True,
+        'filename': compdb_entry.filename,
+        'stdout_text': stdout_text,
+        'stderr_text': stderr_text,
+    }
 
 
 class _CompilerDispatcher(object):
   """Multiprocessing controller for running clang tools in parallel."""
 
-  def __init__(self, toolname, tool_args, build_directory, filenames):
+  def __init__(self, toolname, tool_args, build_directory, compdb_entries):
     """Initializer method.
 
     Args:
       toolname: Path to the tool to execute.
       tool_args: Arguments to be passed to the tool. Can be None.
       build_directory: Directory that contains the compile database.
-      filenames: The files to run the tool over.
+      compdb_entries: The files and args to run the tool over.
     """
     self.__toolname = toolname
     self.__tool_args = tool_args
     self.__build_directory = build_directory
-    self.__filenames = filenames
+    self.__compdb_entries = compdb_entries
     self.__success_count = 0
     self.__failed_count = 0
 
@@ -234,7 +267,7 @@
     result_iterator = pool.imap_unordered(
         functools.partial(_ExecuteTool, self.__toolname, self.__tool_args,
                           self.__build_directory),
-                          self.__filenames)
+                          self.__compdb_entries)
     for result in result_iterator:
       self.__ProcessResult(result)
     sys.stderr.write('\n')
@@ -255,7 +288,7 @@
       sys.stderr.write(result['stderr_text'])
       sys.stderr.write('\n')
     done_count = self.__success_count + self.__failed_count
-    percentage = (float(done_count) / len(self.__filenames)) * 100
+    percentage = (float(done_count) / len(self.__compdb_entries)) * 100
     sys.stderr.write(
         'Processed %d files with %s tool (%d failures) [%.2f%%]\r' %
         (done_count, self.__toolname, self.__failed_count, percentage))
@@ -321,26 +354,25 @@
     with open(os.path.join(args.p, 'compile_commands.json'), 'w') as f:
       f.write(json.dumps(compile_commands, indent=2))
 
-  if args.all:
-    source_filenames = set(_GetFilesFromCompileDB(args.p))
+  compdb_entries = set(_GetEntriesFromCompileDB(args.p, source_filenames))
 
   if args.shard:
-    total_length = len(source_filenames)
+    total_length = len(compdb_entries)
     match = re.match(r'(\d+)-of-(\d+)$', args.shard)
     # Input is 1-based, but modular arithmetic is 0-based.
     shard_number = int(match.group(1)) - 1
     shard_count = int(match.group(2))
-    source_filenames = [
-        f[1] for f in enumerate(sorted(source_filenames))
-        if f[0] % shard_count == shard_number
+    compdb_entries = [
+        f for i, f in enumerate(sorted(compdb_entries))
+        if i % shard_count == shard_number
     ]
     print 'Shard %d-of-%d will process %d entries out of %d' % (
-        shard_number, shard_count, len(source_filenames), total_length)
+        shard_number, shard_count, len(compdb_entries), total_length)
 
   dispatcher = _CompilerDispatcher(os.path.join(tool_path, args.tool),
                                    args.tool_arg,
                                    args.p,
-                                   source_filenames)
+                                   compdb_entries)
   dispatcher.Run()
   return -dispatcher.failed_count
 
diff --git a/tools/code_coverage/coverage.py b/tools/code_coverage/coverage.py
index 962f8515..71957a1 100755
--- a/tools/code_coverage/coverage.py
+++ b/tools/code_coverage/coverage.py
@@ -91,8 +91,9 @@
 
 # Absolute path to the code coverage tools binary.
 LLVM_BUILD_DIR = clang_update.LLVM_BUILD_DIR
-LLVM_COV_PATH = os.path.join(LLVM_BUILD_DIR, 'bin', 'llvm-cov')
-LLVM_PROFDATA_PATH = os.path.join(LLVM_BUILD_DIR, 'bin', 'llvm-profdata')
+LLVM_BIN_DIR = os.path.join(LLVM_BUILD_DIR, 'bin')
+LLVM_COV_PATH = os.path.join(LLVM_BIN_DIR, 'llvm-cov')
+LLVM_PROFDATA_PATH = os.path.join(LLVM_BIN_DIR, 'llvm-profdata')
 
 # Build directory, the value is parsed from command line arguments.
 BUILD_DIR = None
@@ -130,7 +131,8 @@
 LOGS_DIR_NAME = 'logs'
 
 # Used to extract a mapping between directories and components.
-COMPONENT_MAPPING_URL = 'https://storage.googleapis.com/chromium-owners/component_map.json'
+COMPONENT_MAPPING_URL = (
+    'https://storage.googleapis.com/chromium-owners/component_map.json')
 
 # Caches the results returned by _GetBuildArgs, don't use this variable
 # directly, call _GetBuildArgs instead.
@@ -400,6 +402,16 @@
     return 'mac'
 
 
+def _GetPathWithLLVMSymbolizerDir():
+  """Add llvm-symbolizer directory to path for symbolized stacks."""
+  path = os.getenv('PATH')
+  dirs = path.split(os.pathsep)
+  if LLVM_BIN_DIR in dirs:
+    return path
+
+  return path + os.pathsep + LLVM_BIN_DIR
+
+
 def _GetTargetOS():
   """Returns the target os specified in args.gn file.
 
@@ -1009,10 +1021,15 @@
     output = subprocess.check_output(
         shlex.split(command),
         stderr=subprocess.STDOUT,
-        env={'LLVM_PROFILE_FILE': expected_profraw_file_path})
+        env={
+            'LLVM_PROFILE_FILE': expected_profraw_file_path,
+            'PATH': _GetPathWithLLVMSymbolizerDir()
+        })
   except subprocess.CalledProcessError as e:
     output = e.output
-    logging.warning('Command: "%s" exited with non-zero return code.', command)
+    logging.warning(
+        'Command: "%s" exited with non-zero return code. Output:\n%s', command,
+        output)
 
   return output
 
@@ -1045,7 +1062,10 @@
   try:
     output = subprocess.check_output(
         shlex.split(command),
-        env={'LLVM_PROFILE_FILE': iossim_profraw_file_path})
+        env={
+            'LLVM_PROFILE_FILE': iossim_profraw_file_path,
+            'PATH': _GetPathWithLLVMSymbolizerDir()
+        })
   except subprocess.CalledProcessError as e:
     # iossim emits non-zero return code even if tests run successfully, so
     # ignore the return code.
diff --git a/tools/mb/docs/user_guide.md b/tools/mb/docs/user_guide.md
index ba8bff9..fd5823b5 100644
--- a/tools/mb/docs/user_guide.md
+++ b/tools/mb/docs/user_guide.md
@@ -186,21 +186,6 @@
 and then takes all of the files in the isolate and writes them into a single
 zip file that can then easily be redistributed.
 
-### mb gerrit-buildbucket-config
-
-Generates a gerrit buildbucket configuration file and prints it to
-stdout. This file contains the list of trybots shown in gerrit's UI.
-
-The master copy of the buildbucket.config file lives
-in a separate branch of the chromium repository. Run `mb
-gerrit-buildbucket-config > buildbucket.config.new && git fetch origin
-refs/meta/config:refs/remotes/origin/meta/config && git checkout
--t -b meta_config origin/meta/config && mv buildbucket.config.new
-buildbucket.config` to update the file.
-
-Note that after committing, `git cl upload` will not work. Instead, use `git
-push origin HEAD:refs/for/refs/meta/config` to upload the CL for review.
-
 ## Isolates and Swarming
 
 `mb gen` is also responsible for generating the `.isolate` and
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index 57ddca2..94bf68e 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -54,7 +54,6 @@
     self.sep = os.sep
     self.args = argparse.Namespace()
     self.configs = {}
-    self.luci_tryservers = {}
     self.masters = {}
     self.mixins = {}
 
@@ -222,14 +221,6 @@
                       help='path to config file (default is %(default)s)')
     subp.set_defaults(func=self.CmdValidate)
 
-    subp = subps.add_parser('gerrit-buildbucket-config',
-                            help='Print buildbucket.config for gerrit '
-                            '(see MB user guide)')
-    subp.add_argument('-f', '--config-file', metavar='PATH',
-                      default=self.default_config,
-                      help='path to config file (default is %(default)s)')
-    subp.set_defaults(func=self.CmdBuildbucket)
-
     subp = subps.add_parser('zip',
                             help='generate a .zip containing the files needed '
                                  'for a given binary')
@@ -483,25 +474,6 @@
             ('cpu', 'x86-64'),
             os_dim]
 
-  def CmdBuildbucket(self):
-    self.ReadConfigFile()
-
-    self.Print('# This file was generated using '
-               '"tools/mb/mb.py gerrit-buildbucket-config".')
-
-    for luci_tryserver in sorted(self.luci_tryservers):
-      self.Print('[bucket "luci.%s"]' % luci_tryserver)
-      for bot in sorted(self.luci_tryservers[luci_tryserver]):
-        self.Print('\tbuilder = %s' % bot)
-
-    for master in sorted(self.masters):
-      if master.startswith('tryserver.'):
-        self.Print('[bucket "master.%s"]' % master)
-        for bot in sorted(self.masters[master]):
-          self.Print('\tbuilder = %s' % bot)
-
-    return 0
-
   def CmdValidate(self, print_ok=True):
     errs = []
 
@@ -665,7 +637,6 @@
                  (self.args.config_file, e))
 
     self.configs = contents['configs']
-    self.luci_tryservers = contents.get('luci_tryservers', {})
     self.masters = contents['masters']
     self.mixins = contents['mixins']
 
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index cea0cb3..c2bd4219 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -260,7 +260,10 @@
       'Chromium Linux Goma GCE Staging': 'release_bot',
       'Chromium Mac Goma GCE Staging': 'release_bot',
       'CrWinClangGomaGCEStaging': 'win_clang_release_bot_disable_nacl',
+      'Chromium Linux Goma RBE Staging (clobber)': 'release_bot',
       'Chromium Linux Goma RBE Staging': 'release_bot',
+      'Chromium Linux Goma RBE Staging (dbg) (clobber)': 'debug_bot',
+      'Chromium Linux Goma RBE Staging (dbg)': 'debug_bot',
     },
 
     'chromium.gpu': {
@@ -2122,8 +2125,4 @@
       'gn_args': 'target_cpu="x86"',
     },
   },
-
-  'luci_tryservers': {
-    'chromium.try': [ 'linux_chromium_rel_ng' ],
-  },
 }
diff --git a/tools/mb/mb_unittest.py b/tools/mb/mb_unittest.py
index 294a166..bf6a771 100755
--- a/tools/mb/mb_unittest.py
+++ b/tools/mb/mb_unittest.py
@@ -190,10 +190,6 @@
       'try_builder2': 'fake_config',
     },
   },
-  'luci_tryservers': {
-    'luci_tryserver1': ['luci_builder1'],
-    'luci_tryserver2': ['luci_builder2'],
-  },
   'configs': {},
   'mixins': {},
 }
@@ -631,22 +627,6 @@
     mbw.files[mbw.default_config] = TEST_BAD_CONFIG
     self.check(['validate'], mbw=mbw, ret=1)
 
-  def test_buildbucket(self):
-    mbw = self.fake_mbw()
-    mbw.files[mbw.default_config] = TRYSERVER_CONFIG
-    self.check(['gerrit-buildbucket-config'], mbw=mbw,
-               ret=0,
-               out=('# This file was generated using '
-                    '"tools/mb/mb.py gerrit-buildbucket-config".\n'
-                    '[bucket "luci.luci_tryserver1"]\n'
-                    '\tbuilder = luci_builder1\n'
-                    '[bucket "luci.luci_tryserver2"]\n'
-                    '\tbuilder = luci_builder2\n'
-                    '[bucket "master.tryserver.chromium.linux"]\n'
-                    '\tbuilder = try_builder\n'
-                    '[bucket "master.tryserver.chromium.mac"]\n'
-                    '\tbuilder = try_builder2\n'))
-
   def test_build_command_unix(self):
     files = {
       '/fake_src/out/Default/toolchain.ninja': '',
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 9d10cb5ad..37116dc 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -5940,6 +5940,14 @@
   </description>
 </action>
 
+<action name="InProductHelp.ShouldTriggerHelpUI.IPH_HomePageButton">
+  <owner>danielpark@chromium.org</owner>
+  <description>
+    The feature engagement tracker tried to determine whether in-product help
+    should be shown to the user.
+  </description>
+</action>
+
 <action name="InProductHelp.ShouldTriggerHelpUI.IPH_IncognitoWindow">
   <owner>nyquist@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
@@ -6189,6 +6197,14 @@
 </action>
 
 <action
+    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_HomePageButton">
+  <owner>danielpark@chromium.org</owner>
+  <description>
+    A user action that could have triggered In-Product Help did not.
+  </description>
+</action>
+
+<action
     name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_IncognitoWindow">
   <owner>nyquist@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
@@ -6415,6 +6431,12 @@
 </action>
 
 <action
+    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_HomePageButton">
+  <owner>danielpark@chromium.org</owner>
+  <description>A user action triggered In-Product Help.</description>
+</action>
+
+<action
     name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_IncognitoWindow">
   <owner>nyquist@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
@@ -6563,6 +6585,15 @@
 </action>
 
 <action
+    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_HomePageButton">
+  <owner>danielpark@chromium.org</owner>
+  <description>
+    A user action would have triggered In-Product Help, but the feature was
+    configured for tracking only.
+  </description>
+</action>
+
+<action
     name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_IncognitoWindow">
   <owner>nyquist@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
@@ -12327,6 +12358,14 @@
   </description>
 </action>
 
+<action name="MobileTabReturnedToCurrentTab">
+  <owner>rlanday@chromium.org</owner>
+  <description>
+    User in the Android tab switcher returned to the tab that was active when
+    the tab switcher was opened.
+  </description>
+</action>
+
 <action name="MobileTabStripCloseTab">
   <obsolete>Deprecated as of 5/2015</obsolete>
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
@@ -12423,6 +12462,14 @@
   </description>
 </action>
 
+<action name="MobileToolbarStackViewButtonInStackView">
+  <owner>rlanday@chromium.org</owner>
+  <description>
+    User in the Android tab switcher tapped the tab switcher button on the
+    toolbar to leave the tab switcher.
+  </description>
+</action>
+
 <action name="MobileToolbarStackViewNewTab">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
@@ -20142,6 +20189,7 @@
   <suffix name="DownloadPage" label="For DownloadPage feature."/>
   <suffix name="DownloadPageScreenshot"
       label="For DownloadPageScreenshot feature."/>
+  <suffix name="HomePageButton" label="For HomePageButton feature."/>
   <suffix name="IncognitoWindow" label="For IncognitoWindow feature."/>
   <suffix name="MediaDownload" label="For MediaDownload feature."/>
   <suffix name="NewIncognitoTabTip" label="For NewIncognitoTabTip feature."/>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index c97d158..5666630c 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3110,6 +3110,7 @@
   <int value="199" label="SYNC_COMPOSITOR_NO_BEGIN_FRAME"/>
   <int value="200" label="WEBUI_BAD_HOST_ACCESS"/>
   <int value="201" label="RFMF_BLOB_URL_TOKEN_FOR_NON_BLOB_URL"/>
+  <int value="202" label="PERMISSION_SERVICE_BAD_PERMISSION_DESCRIPTOR"/>
 </enum>
 
 <enum name="BadMessageReasonExtensions">
@@ -8187,12 +8188,28 @@
   <int value="1" label="Click"/>
 </enum>
 
+<enum name="CrosSystemTrayToggleExpanded">
+  <int value="0" label="Toggled by button"/>
+  <int value="1" label="Toggled by gesture"/>
+</enum>
+
 <enum name="CrostiniAppLaunchAppType">
   <int value="0" label="Unknown App"/>
   <int value="1" label="Terminal"/>
   <int value="2" label="Registered App"/>
 </enum>
 
+<enum name="CrostiniSetupResult">
+  <int value="0" label="Not Started"/>
+  <int value="1" label="User Cancelled"/>
+  <int value="2" label="Success"/>
+  <int value="3" label="Error Loading Termina"/>
+  <int value="4" label="Error Starting Concierge"/>
+  <int value="5" label="Error Creating Disk Image"/>
+  <int value="6" label="Error Starting Termina"/>
+  <int value="7" label="Error Starting Container"/>
+</enum>
+
 <enum name="CrosTPMDictionaryAttackResetStatusEnum">
   <int value="0" label="Reset not necessary"/>
   <int value="1" label="Reset attempt succeeded"/>
@@ -15402,6 +15419,7 @@
   <int value="1249" label="INPUTMETHODPRIVATE_GETCOMPOSITIONBOUNDS"/>
   <int value="1250" label="FILEMANAGERPRIVATE_ISCROSTINIENABLED"/>
   <int value="1251" label="FILEMANAGERPRIVATE_MOUNTCROSTINICONTAINER"/>
+  <int value="1252" label="CECPRIVATE_QUERYDISPLAYCECPOWERSTATE"/>
 </enum>
 
 <enum name="ExtensionIconState">
@@ -18598,6 +18616,7 @@
   <int value="2432" label="KeyboardApiGetLayoutMap"/>
   <int value="2433" label="WebRtcVaapiHWVP8Encoding"/>
   <int value="2434" label="PerformanceResourceTimingInitiatorType"/>
+  <int value="2435" label="PaymentRequestInvalidCurrencyCode"/>
 </enum>
 
 <enum name="FeedbackSource">
@@ -38932,6 +38951,7 @@
   <int value="33" label="InternalInspector"/>
   <int value="34" label="InternalAnimation"/>
   <int value="35" label="InternalAccessibility"/>
+  <int value="36" label="InternalWorker"/>
 </enum>
 
 <enum name="RendererSchedulerTaskUseCase">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 5548cc7..b21cc1d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -10773,6 +10773,15 @@
   </summary>
 </histogram>
 
+<histogram name="ChromeOS.SystemTray.ToggleExpanded"
+    enum="CrosSystemTrayToggleExpanded">
+  <owner>tetsui@chromium.org</owner>
+  <summary>
+    An enum value how system tray bubble is expanded or collapsed. It can be
+    toggled by the button and touch gesture.
+  </summary>
+</histogram>
+
 <histogram name="ChromiumAndroidLinker.BrowserLoadTime" units="ms">
   <owner>rsesek@chromium.org</owner>
   <summary>
@@ -13664,6 +13673,15 @@
   </summary>
 </histogram>
 
+<histogram name="Crostini.SetupResult" enum="CrostiniSetupResult">
+  <owner>benwells@chromium.org</owner>
+  <owner>tbuckley@chromium.org</owner>
+  <summary>
+    Recorded each time the user initiates the Crostini setup UI, recording the
+    result of the setup.
+  </summary>
+</histogram>
+
 <histogram name="CryptAuth.Enrollment.Result" enum="BooleanSuccess">
   <owner>jhawkins@chromium.org</owner>
   <summary>
@@ -37190,6 +37208,14 @@
   </summary>
 </histogram>
 
+<histogram name="Media.EME.MediaCryptoAvailable" enum="BooleanAvailable">
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    Whether MediaCrypto is available on a MediaDrm-based CDM. Reported once per
+    MediaDrmBridge creation. In normal cases it should always be available.
+  </summary>
+</histogram>
+
 <histogram name="Media.EME.MojoCdm.ConnectionError"
     enum="BooleanConnectionError">
   <owner>media-dev@chromium.org</owner>
@@ -111469,6 +111495,7 @@
       label="In product help download page for screenshot."/>
   <suffix name="IPH_DownloadSettings"
       label="In product help to access download settings from download home."/>
+  <suffix name="IPH_HomePageButton" label="In product help home page button."/>
   <suffix name="IPH_IncognitoWindow" label="In product help incognito window."/>
   <suffix name="IPH_MediaDownload" label="In product help media download."/>
   <suffix name="IPH_NewIncognitoTabTip"
diff --git a/tools/perf/contrib/network_service/loading.py b/tools/perf/contrib/network_service/loading.py
index 83cfbc8..2f88a79a 100644
--- a/tools/perf/contrib/network_service/loading.py
+++ b/tools/perf/contrib/network_service/loading.py
@@ -134,8 +134,9 @@
   _RenameChartsAndPointsWithSuffix(enabled_charts, '_enabled')
   _RenameChartsAndPointsWithSuffix(control_charts, '_control')
   _RenameChartsAndPointsWithSuffix(diff_charts, '_diff')
-  _MergeCharts(enabled_charts, control_charts)
-  _MergeCharts(enabled_charts, diff_charts)
+  # TODO(crbug.com/840524): Perf Dashboard doesn't handle large JSON correctly,
+  # we should merge all three charts after it's fixed.
+  enabled_chart_json['charts'] = diff_charts
 
 @benchmark.Owner(emails=['chongz@chromium.org'])
 class LoadingDesktopNetworkService(loading.LoadingDesktop):
diff --git a/tools/perf/core/results_dashboard.py b/tools/perf/core/results_dashboard.py
index 99a0142..078bed9 100755
--- a/tools/perf/core/results_dashboard.py
+++ b/tools/perf/core/results_dashboard.py
@@ -19,6 +19,7 @@
 import traceback
 import urllib
 import urllib2
+import zlib
 
 from core import path_util
 
@@ -492,7 +493,7 @@
     raise SendResultsRetryException()
 
 def _Httplib2Request(url, data, oauth_token):
-  data = urllib.urlencode({'data': data})
+  data = zlib.compress(data)
   headers = {
       'Authorization': 'Bearer %s' % oauth_token,
       'User-Agent': 'perf-uploader/1.0'
diff --git a/ui/aura/window_tree_host_platform.cc b/ui/aura/window_tree_host_platform.cc
index e2859bc..518c650 100644
--- a/ui/aura/window_tree_host_platform.cc
+++ b/ui/aura/window_tree_host_platform.cc
@@ -81,7 +81,10 @@
 WindowTreeHostPlatform::~WindowTreeHostPlatform() {
   DestroyCompositor();
   DestroyDispatcher();
-  platform_window_->Close();
+
+  // |platform_window_| might have already been destroyed by this time.
+  if (platform_window_)
+    platform_window_->Close();
 }
 
 ui::EventSource* WindowTreeHostPlatform::GetEventSource() {
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
index 6ebf09f..1285dec 100644
--- a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
+++ b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
@@ -159,7 +159,10 @@
    * Start crostini container and mount it.
    */
   mount: function() {
-    chrome.fileManagerPrivate.mountCrostiniContainer();
+    chrome.fileManagerPrivate.mountCrostiniContainer((success) => {
+      // TODO(crbug.com/834103): implement crostini error handling.
+      console.debug('mountCrostiniContainer success: ', success);
+    });
   },
 };
 
diff --git a/ui/file_manager/integration_tests/audio_player/click_control_buttons.js b/ui/file_manager/integration_tests/audio_player/click_control_buttons.js
index 8582c7e..c14d7232 100644
--- a/ui/file_manager/integration_tests/audio_player/click_control_buttons.js
+++ b/ui/file_manager/integration_tests/audio_player/click_control_buttons.js
@@ -6,8 +6,8 @@
 
 /**
  * Confirms that clicking the play button changes the audio player state and
- * updates the play button's label.
- * @return {Promise} Promise to be fulfilled with on success.
+ * updates the play button label.
+ * @return {Promise} Promise to be fulfilled on success.
  */
 testcase.togglePlayState = function() {
   var openAudio = launch('local', 'downloads', [ENTRIES.beautiful]);
@@ -50,9 +50,9 @@
 };
 
 /**
- * Confirms that the AudioPlayer default volume is 50 and that clicking the
- * volume button mutes / unmutes the volume label.
- * @return {Promise} Promise to be fulfilled with on success.
+ * Confirms that the AudioPlayer default volume is 50, and that clicking the
+ * volume button mutes / unmutes the volume.
+ * @return {Promise} Promise to be fulfilled on success.
  */
 testcase.changeVolumeLevel = function() {
   var openAudio = launch('local', 'downloads', [ENTRIES.beautiful]);
@@ -89,9 +89,9 @@
 };
 
 /**
- * Confirm that clicking "Next" and track on playlist change the current track
- * and play state correctly.
- * @return {Promise} Promise to be fulfilled with on success.
+ * Confirms that the Audio Player active track changes and plays when a user
+ * clicks the "next" button.
+ * @return {Promise} Promise to be fulfilled on success.
  */
 testcase.changeTracks = function() {
   var openAudio = launch('local', 'downloads',
@@ -100,71 +100,168 @@
   return openAudio.then(function(args) {
     appId = args[0];
   }).then(function() {
-    // While playing, the play/pause button should have 'Pause' label.
-    return remoteCallAudioPlayer.waitForElement(
-        appId, ['#play[aria-label="Pause"]']);
+    // Audio player starts playing automatically
+    return Promise.all([
+      remoteCallAudioPlayer.waitForElement(
+          appId, 'audio-player[playing]'),
+      remoteCallAudioPlayer.waitForElement(
+          appId, ['#play[aria-label="Pause"]'])
+    ]);
   }).then(function() {
-    // Clicking the pause button should change the playback state to pause.
-    return remoteCallAudioPlayer.callRemoteTestUtil(
-        'fakeMouseClick', appId, ['#play']);
-  }).then(function() {
-    return remoteCallAudioPlayer.waitForElement(
-        appId, 'audio-player:not([playing])');
-  }).then(function() {
-    // The first track should be active.
+    // ... and track 0 should be active.
     return remoteCallAudioPlayer.waitForElement(
         appId, ['.track[index="0"][active]']);
   }).then(function() {
-    // Clicking next button should activate the second track and start playing.
+    // Clicking the play button should
+    return remoteCallAudioPlayer.callRemoteTestUtil(
+        'fakeMouseClick', appId, ['#play']);
+  }).then(function() {
+    // ... change the playback state to pause
+    return Promise.all([
+      remoteCallAudioPlayer.waitForElement(
+          appId, 'audio-player:not([playing])'),
+      remoteCallAudioPlayer.waitForElement(
+          appId, ['#play[aria-label="Play"]'])
+    ]);
+  }).then(function() {
+    // ... and track 0 should still be active.
+    return remoteCallAudioPlayer.waitForElement(
+        appId, ['.track[index="0"][active]']);
+  }).then(function() {
+    // Clicking the player's "next" button should
     return remoteCallAudioPlayer.callRemoteTestUtil(
         'fakeMouseClick', appId, ['#next']);
   }).then(function() {
-    return remoteCallAudioPlayer.waitForElement(
-        appId, ['.track[index="1"][active]']);
+    // ... activate and play track 1.
+    return Promise.all([
+      remoteCallAudioPlayer.waitForElement(
+          appId, ['.track[index="1"][active]']),
+      remoteCallAudioPlayer.waitForElement(
+          appId, 'audio-player[playing]')
+    ]);
+  });
+};
+
+/**
+ * Confirms that the track-list expands when the play-list button is clicked,
+ * then clicking on a track in the play-list, plays that track.
+ * @return {Promise} Promise to be fulfilled on success.
+ */
+testcase.changeTracksPlayList = function() {
+  var openAudio = launch('local', 'downloads',
+      [ENTRIES.beautiful, ENTRIES.newlyAdded]);
+  var appId;
+  return openAudio.then(function(args) {
+    appId = args[0];
   }).then(function() {
-    return remoteCallAudioPlayer.waitForElement(
-        appId, 'audio-player[playing]');
+    // Audio player starts playing automatically
+    return Promise.all([
+      remoteCallAudioPlayer.waitForElement(
+          appId, 'audio-player[playing]'),
+      remoteCallAudioPlayer.waitForElement(
+          appId, ['#play[aria-label="Pause"]'])
+    ]);
   }).then(function() {
-    // Pause to prepare for remaining steps.
+    // ... and track 0 should be active.
+    return remoteCallAudioPlayer.waitForElement(
+        appId, ['.track[index="0"][active]']);
+  }).then(function() {
+    // Clicking the play button should
     return remoteCallAudioPlayer.callRemoteTestUtil(
         'fakeMouseClick', appId, ['#play']);
   }).then(function() {
-    return remoteCallAudioPlayer.waitForElement(
-        appId, 'audio-player:not([playing])');
+    // ... change the playback state to pause,
+    return Promise.all([
+      remoteCallAudioPlayer.waitForElement(
+          appId, 'audio-player:not([playing])'),
+      remoteCallAudioPlayer.waitForElement(
+          appId, ['#play[aria-label="Play"]'])
+    ]);
   }).then(function() {
-    // Clicking playlist button should expand track list.
+    // ... and track 0 should still be active.
+    return remoteCallAudioPlayer.waitForElement(
+        appId, ['.track[index="0"][active]']);
+  }).then(function() {
+    // Clicking the play-list button should
     return remoteCallAudioPlayer.callRemoteTestUtil(
         'fakeMouseClick', appId, ['#playList']);
   }).then(function() {
+    // ... expand the Audio Player track-list.
     return remoteCallAudioPlayer.waitForElement(
         appId, 'track-list[expanded]');
   }).then(function() {
-    // Clicking the first track should make it active and start playing it.
+    // Clicking on a track (track 0 here) should
     return remoteCallAudioPlayer.callRemoteTestUtil(
         'fakeMouseClick', appId, ['.track[index="0"]']);
   }).then(function() {
-    return remoteCallAudioPlayer.waitForElement(
-        appId, '.track[index="0"][active]');
+    // ... activate and start playing that track.
+    return Promise.all([
+      remoteCallAudioPlayer.waitForElement(
+          appId, '.track[index="0"][active]'),
+      remoteCallAudioPlayer.waitForElement(
+          appId, 'audio-player[playing]')
+    ]);
+  });
+};
+
+/**
+ * Confirms that the track-list expands when the play-list button is clicked,
+ * then clicking on a track 'Play' icon in the play-list, plays that track.
+ * @return {Promise} Promise to be fulfilled on success.
+ */
+testcase.changeTracksPlayListIcon = function() {
+  var openAudio = launch('local', 'downloads',
+      [ENTRIES.beautiful, ENTRIES.newlyAdded]);
+  var appId;
+  return openAudio.then(function(args) {
+    appId = args[0];
   }).then(function() {
-    return remoteCallAudioPlayer.waitForElement(
-        appId, 'audio-player[playing]');
+    // Audio player starts playing automatically
+    return Promise.all([
+      remoteCallAudioPlayer.waitForElement(
+          appId, 'audio-player[playing]'),
+      remoteCallAudioPlayer.waitForElement(
+          appId, ['#play[aria-label="Pause"]'])
+    ]);
   }).then(function() {
-    // Pause to prepare for remaining steps.
+    // ... and track 0 should be active.
+    return remoteCallAudioPlayer.waitForElement(
+        appId, ['.track[index="0"][active]']);
+  }).then(function() {
+    // Clicking the play button should
     return remoteCallAudioPlayer.callRemoteTestUtil(
         'fakeMouseClick', appId, ['#play']);
   }).then(function() {
-    return remoteCallAudioPlayer.waitForElement(
-        appId, 'audio-player:not([playing])');
+    // ... change the playback state to pause,
+    return Promise.all([
+      remoteCallAudioPlayer.waitForElement(
+          appId, 'audio-player:not([playing])'),
+      remoteCallAudioPlayer.waitForElement(
+          appId, ['#play[aria-label="Play"]'])
+    ]);
   }).then(function() {
-    // Clicking the play icon on the second should make it active, and start
-    // playing.
+    // ... and track 0 should still be active.
+    return remoteCallAudioPlayer.waitForElement(
+        appId, ['.track[index="0"][active]']);
+  }).then(function() {
+    // Clicking the play-list button should
+    return remoteCallAudioPlayer.callRemoteTestUtil(
+        'fakeMouseClick', appId, ['#playList']);
+  }).then(function() {
+    // ... expand the Audio Player track-list.
+    return remoteCallAudioPlayer.waitForElement(
+        appId, 'track-list[expanded]');
+  }).then(function() {
+    // Clicking a track (track 1 here) 'Play' icon should
     return remoteCallAudioPlayer.callRemoteTestUtil(
         'fakeMouseClick', appId, ['.track[index="1"] .icon']);
   }).then(function() {
-    return remoteCallAudioPlayer.waitForElement(
-        appId, '.track[index="1"][active]');
-  }).then(function() {
-    return remoteCallAudioPlayer.waitForElement(
-        appId, 'audio-player[playing]');
+    // ... activate and start playing that track.
+    return Promise.all([
+      remoteCallAudioPlayer.waitForElement(
+          appId, '.track[index="1"][active]'),
+      remoteCallAudioPlayer.waitForElement(
+          appId, 'audio-player[playing]')
+    ]);
   });
 };
diff --git a/ui/gl/gl_surface_presentation_helper.cc b/ui/gl/gl_surface_presentation_helper.cc
index 2fd3aed..e9ecc50 100644
--- a/ui/gl/gl_surface_presentation_helper.cc
+++ b/ui/gl/gl_surface_presentation_helper.cc
@@ -176,7 +176,6 @@
         };
 
     if (frame.result != gfx::SwapResult::SWAP_ACK) {
-      DCHECK(!frame.timer);
       frame_presentation_callback(gfx::PresentationFeedback());
       continue;
     }
diff --git a/ui/ozone/platform/drm/gpu/drm_device.cc b/ui/ozone/platform/drm/gpu/drm_device.cc
index 632cd0a..ee71883 100644
--- a/ui/ozone/platform/drm/gpu/drm_device.cc
+++ b/ui/ozone/platform/drm/gpu/drm_device.cc
@@ -236,6 +236,25 @@
   return result;
 }
 
+bool GetDrmProperty(int fd,
+                    drmModeObjectPropertiesPtr properties,
+                    const char* name,
+                    DrmDevice::Property* property) {
+  for (uint32_t i = 0; i < properties->count_props; ++i) {
+    ScopedDrmPropertyPtr drm_property(
+        drmModeGetProperty(fd, properties->props[i]));
+    if (strcmp(drm_property->name, name))
+      continue;
+
+    property->id = drm_property->prop_id;
+    property->value = properties->prop_values[i];
+    if (property->id)
+      return true;
+  }
+
+  return false;
+}
+
 }  // namespace
 
 class DrmDevice::PageFlipManager {
@@ -371,6 +390,34 @@
   watcher_.reset(
       new IOWatcher(file_.GetPlatformFile(), page_flip_manager_.get()));
 
+  return InitializeProperties();
+}
+
+bool DrmDevice::InitializeProperties() {
+  int fd = file_.GetPlatformFile();
+  ScopedDrmResourcesPtr resources(drmModeGetResources(fd));
+
+  for (int i = 0; i < resources->count_crtcs; ++i) {
+    crtc_properties_.push_back({});
+    CrtcProperties& p = crtc_properties_.back();
+    p.id = resources->crtcs[i];
+
+    ScopedDrmObjectPropertyPtr props(drmModeObjectGetProperties(
+        fd, resources->crtcs[i], DRM_MODE_OBJECT_CRTC));
+    if (!props) {
+      LOG(ERROR) << "Failed to get CRTC properties for crtc_id=" << p.id;
+      continue;
+    }
+
+    // These properties are optional. If they don't exist we can tell by the
+    // invalid ID.
+    GetDrmProperty(fd, props.get(), "CTM", &p.ctm);
+    GetDrmProperty(fd, props.get(), "GAMMA_LUT", &p.gamma_lut);
+    GetDrmProperty(fd, props.get(), "GAMMA_LUT_SIZE", &p.gamma_lut_size);
+    GetDrmProperty(fd, props.get(), "DEGAMMA_LUT", &p.degamma_lut);
+    GetDrmProperty(fd, props.get(), "DEGAMMA_LUT_SIZE", &p.degamma_lut_size);
+  }
+
   return true;
 }
 
@@ -694,131 +741,73 @@
     const std::vector<float>& correction_matrix) {
   const bool should_set_gamma_properties =
       !degamma_lut.empty() || !gamma_lut.empty();
+  const CrtcProperties* crtc_props = GetCrtcProperties(crtc_id);
+  if (!crtc_props) {
+    LOG(ERROR) << "Unknown CRTC ID=" << crtc_id;
+    return false;
+  }
 
-  ScopedDrmCrtcPtr crtc(drmModeGetCrtc(file_.GetPlatformFile(), crtc_id));
-  // TODO(dcastagna): Precompute and cache the return value of
-  // HasColorCorrectionMatrix when we initialize DrmDevice.
-  // We currently assume that if a per-CRTC CTM is not available, per-plane
-  // CTMs will be. We can make this more explicit once we address this TODO.
-  if (!HasColorCorrectionMatrix(file_.GetPlatformFile(), crtc.get()) &&
-      !should_set_gamma_properties) {
-    if (!correction_matrix.empty()) {
-      return plane_manager_->SetColorCorrectionOnAllCrtcPlanes(
-          crtc_id, CreateCTMBlob(correction_matrix));
-    } else {
+  if (correction_matrix.empty()) {
+    LOG(ERROR) << "CTM is empty. Expected a 3x3 matrix.";
+    return false;
+  }
+
+  if (crtc_props->ctm.id) {
+    ScopedDrmColorCtmPtr ctm_blob_data = CreateCTMBlob(correction_matrix);
+    if (!SetBlobProperty(file_.GetPlatformFile(), crtc_id, DRM_MODE_OBJECT_CRTC,
+                         crtc_props->ctm.id, "CTM",
+                         reinterpret_cast<unsigned char*>(ctm_blob_data.get()),
+                         sizeof(drm_color_ctm))) {
       return false;
     }
+  } else if (!should_set_gamma_properties) {
+    return plane_manager_->SetColorCorrectionOnAllCrtcPlanes(
+        crtc_id, CreateCTMBlob(correction_matrix));
   }
 
-  ScopedDrmObjectPropertyPtr crtc_props(drmModeObjectGetProperties(
-      file_.GetPlatformFile(), crtc_id, DRM_MODE_OBJECT_CRTC));
+  if (!should_set_gamma_properties)
+    return true;
 
-  // Extract only the needed properties.
-  int max_num_properties_expected = 1;
-  if (should_set_gamma_properties)
-    max_num_properties_expected += 4;
-
-  // The gamma/degamma LUT sizes must be extracted first since they're needed at
-  // the time when we set the gamma/degamma properties. Hence, we'll cache the
-  // gamma/degamma properties and defer setting them later only when needed.
-  uint64_t degamma_lut_size = 0;
-  uint64_t gamma_lut_size = 0;
-  ScopedDrmPropertyPtr degamma_lut_property;
-  uint32_t degamma_lut_property_index = 0;
-  ScopedDrmPropertyPtr gamma_lut_property;
-  uint32_t gamma_lut_property_index = 0;
-  int properties_counter = 0;
-  for (uint32_t i = 0; i < crtc_props->count_props; ++i) {
-    ScopedDrmPropertyPtr property(
-        drmModeGetProperty(file_.GetPlatformFile(), crtc_props->props[i]));
-    if (!property)
-      continue;
-
-    // TODO: Cache those properties when we get the device in order to avoid
-    // looking for them every time.
-    if (should_set_gamma_properties) {
-      if (!strcmp(property->name, "DEGAMMA_LUT_SIZE")) {
-        degamma_lut_size = crtc_props->prop_values[i];
-        ++properties_counter;
-        continue;
-      }
-
-      if (!strcmp(property->name, "GAMMA_LUT_SIZE")) {
-        gamma_lut_size = crtc_props->prop_values[i];
-        ++properties_counter;
-        continue;
-      }
-
-      if (!strcmp(property->name, "DEGAMMA_LUT")) {
-        degamma_lut_property = std::move(property);
-        degamma_lut_property_index = i;
-        ++properties_counter;
-        continue;
-      }
-
-      if (!strcmp(property->name, "GAMMA_LUT")) {
-        gamma_lut_property = std::move(property);
-        gamma_lut_property_index = i;
-        ++properties_counter;
-        continue;
-      }
-    }
-
-    if (!strcmp(property->name, "CTM")) {
-      ScopedDrmColorCtmPtr ctm_blob_data = CreateCTMBlob(correction_matrix);
-      if (!SetBlobProperty(
-              file_.GetPlatformFile(), crtc_id, DRM_MODE_OBJECT_CRTC,
-              crtc_props->props[i], property->name,
-              reinterpret_cast<unsigned char*>(ctm_blob_data.get()),
-              sizeof(drm_color_ctm))) {
-        return false;
-      }
-      ++properties_counter;
-      continue;
-    }
-
-    // Don't waste time checking other properties if all the needed ones are
-    // found.
-    DCHECK_LE(properties_counter, max_num_properties_expected);
-    if (properties_counter == max_num_properties_expected)
-      break;
-  }
-
-  if (should_set_gamma_properties) {
-    if (degamma_lut_size == 0 || gamma_lut_size == 0) {
-      // If we can't find the degamma & gamma lut size, it means the properties
-      // aren't available. We should then use the legacy gamma ramp ioctl.
+  if (!crtc_props->degamma_lut_size.id || !crtc_props->gamma_lut_size.id ||
+      !crtc_props->degamma_lut.id || !crtc_props->gamma_lut.id) {
+    // If we can't find the degamma & gamma lut, it means the properties
+    // aren't available. We should then try to use the legacy gamma ramp ioctl.
+    if (degamma_lut.empty())
       return SetGammaRamp(crtc_id, gamma_lut);
-    }
 
-    if (degamma_lut_property) {
-      ScopedDrmColorLutPtr degamma_blob_data =
-          CreateLutBlob(ResampleLut(degamma_lut, degamma_lut_size));
-      if (!SetBlobProperty(
-              file_.GetPlatformFile(), crtc_id, DRM_MODE_OBJECT_CRTC,
-              crtc_props->props[degamma_lut_property_index],
-              degamma_lut_property->name,
-              reinterpret_cast<unsigned char*>(degamma_blob_data.get()),
-              sizeof(drm_color_lut) * degamma_lut_size)) {
-        return false;
-      }
-    }
+    // We're missing either degamma or gamma lut properties. We shouldn't try to
+    // set just one of them.
+    return false;
+  }
 
-    if (gamma_lut_property) {
-      ScopedDrmColorLutPtr gamma_blob_data =
-          CreateLutBlob(ResampleLut(gamma_lut, gamma_lut_size));
-      if (!SetBlobProperty(
-              file_.GetPlatformFile(), crtc_id, DRM_MODE_OBJECT_CRTC,
-              crtc_props->props[gamma_lut_property_index],
-              gamma_lut_property->name,
-              reinterpret_cast<unsigned char*>(gamma_blob_data.get()),
-              sizeof(drm_color_lut) * gamma_lut_size)) {
-        return false;
-      }
-    }
+  ScopedDrmColorLutPtr degamma_blob_data = CreateLutBlob(
+      ResampleLut(degamma_lut, crtc_props->degamma_lut_size.value));
+  if (!SetBlobProperty(
+          file_.GetPlatformFile(), crtc_id, DRM_MODE_OBJECT_CRTC,
+          crtc_props->degamma_lut.id, "DEGAMMA_LUT",
+          reinterpret_cast<unsigned char*>(degamma_blob_data.get()),
+          sizeof(drm_color_lut) * crtc_props->degamma_lut_size.value)) {
+    return false;
+  }
+
+  ScopedDrmColorLutPtr gamma_blob_data =
+      CreateLutBlob(ResampleLut(gamma_lut, crtc_props->gamma_lut_size.value));
+  if (!SetBlobProperty(
+          file_.GetPlatformFile(), crtc_id, DRM_MODE_OBJECT_CRTC,
+          crtc_props->gamma_lut.id, "GAMMA_LUT",
+          reinterpret_cast<unsigned char*>(gamma_blob_data.get()),
+          sizeof(drm_color_lut) * crtc_props->gamma_lut_size.value)) {
+    return false;
   }
 
   return true;
 }
 
+DrmDevice::CrtcProperties* DrmDevice::GetCrtcProperties(uint32_t crtc_id) {
+  auto it = std::find_if(
+      crtc_properties_.begin(), crtc_properties_.end(),
+      [crtc_id](const CrtcProperties& props) { return props.id == crtc_id; });
+  return it != crtc_properties_.end() ? &(*it) : nullptr;
+}
+
 }  // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_device.h b/ui/ozone/platform/drm/gpu/drm_device.h
index 94cd422..f0372b7 100644
--- a/ui/ozone/platform/drm/gpu/drm_device.h
+++ b/ui/ozone/platform/drm/gpu/drm_device.h
@@ -44,6 +44,27 @@
       base::OnceCallback<void(unsigned int /* frame */,
                               base::TimeTicks /* timestamp */)>;
 
+  struct Property {
+    // Unique identifier for the property. 0 denotes an invalid ID.
+    uint32_t id;
+
+    // Depending on the property, this may be an actual value describing the
+    // property or an ID of another property.
+    uint32_t value;
+  };
+
+  struct CrtcProperties {
+    // Unique identifier for the CRTC. This must be greater than 0 to be valid.
+    uint32_t id;
+
+    // Optional properties.
+    Property ctm;
+    Property gamma_lut;
+    Property gamma_lut_size;
+    Property degamma_lut;
+    Property degamma_lut_size;
+  };
+
   DrmDevice(const base::FilePath& device_path,
             base::File file,
             bool is_primary_device);
@@ -192,9 +213,13 @@
   class IOWatcher;
   class PageFlipManager;
 
+  bool InitializeProperties();
+
   bool SetGammaRamp(uint32_t crtc_id,
                     const std::vector<display::GammaRampRGBEntry>& lut);
 
+  CrtcProperties* GetCrtcProperties(uint32_t crtc_id);
+
   // Path to the DRM device (in sysfs).
   const base::FilePath device_path_;
 
@@ -210,6 +235,8 @@
 
   bool allow_addfb2_modifiers_;
 
+  std::vector<CrtcProperties> crtc_properties_;
+
   DISALLOW_COPY_AND_ASSIGN(DrmDevice);
 };
 
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h b/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h
index 952c6f93..843000a 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h
@@ -41,6 +41,7 @@
       DrmDevice* drm,
       const ScopedDrmObjectPropertyPtr& plane_props) override;
 
+  // TODO(dnicoara): Merge this with DrmDevice::Property.
   struct Property {
     Property();
     bool Initialize(DrmDevice* drm,
diff --git a/ui/views/mus/screen_mus.cc b/ui/views/mus/screen_mus.cc
index 36f721b..8c8dd07f 100644
--- a/ui/views/mus/screen_mus.cc
+++ b/ui/views/mus/screen_mus.cc
@@ -37,7 +37,7 @@
 using Type = display::DisplayList::Type;
 
 ScreenMus::ScreenMus(ScreenMusDelegate* delegate)
-    : delegate_(delegate), display_manager_observer_binding_(this) {
+    : delegate_(delegate), screen_provider_observer_binding_(this) {
   DCHECK(delegate);
   display::Screen::SetScreenInstance(this);
 }
@@ -48,23 +48,23 @@
 }
 
 void ScreenMus::Init(service_manager::Connector* connector) {
-  connector->BindInterface(ui::mojom::kServiceName, &display_manager_);
+  connector->BindInterface(ui::mojom::kServiceName, &screen_provider_);
 
-  ui::mojom::DisplayManagerObserverPtr observer;
-  display_manager_observer_binding_.Bind(mojo::MakeRequest(&observer));
-  display_manager_->AddObserver(std::move(observer));
+  ui::mojom::ScreenProviderObserverPtr observer;
+  screen_provider_observer_binding_.Bind(mojo::MakeRequest(&observer));
+  screen_provider_->AddObserver(std::move(observer));
 
   // We need the set of displays before we can continue. Wait for it.
   //
   // TODO(rockot): Do something better here. This should not have to block tasks
   // from running on the calling thread. http://crbug.com/594852.
-  bool success = display_manager_observer_binding_.WaitForIncomingMethodCall();
+  bool success = screen_provider_observer_binding_.WaitForIncomingMethodCall();
 
   // The WaitForIncomingMethodCall() should have supplied the set of Displays,
   // unless mus is going down, in which case encountered_error() is true, or the
   // call to WaitForIncomingMethodCall() failed.
   if (display_list().displays().empty()) {
-    DCHECK(display_manager_.encountered_error() || !success);
+    DCHECK(screen_provider_.encountered_error() || !success);
     // In this case we install a default display and assume the process is
     // going to exit shortly so that the real value doesn't matter.
     display_list().AddDisplay(
diff --git a/ui/views/mus/screen_mus.h b/ui/views/mus/screen_mus.h
index 4987b07..42c4d15 100644
--- a/ui/views/mus/screen_mus.h
+++ b/ui/views/mus/screen_mus.h
@@ -6,7 +6,7 @@
 #define UI_VIEWS_MUS_SCREEN_MUS_H_
 
 #include "mojo/public/cpp/bindings/binding.h"
-#include "services/ui/public/interfaces/display_manager.mojom.h"
+#include "services/ui/public/interfaces/screen_provider.mojom.h"
 #include "ui/display/screen_base.h"
 #include "ui/views/mus/mus_export.h"
 
@@ -18,9 +18,9 @@
 
 class ScreenMusDelegate;
 
-// Screen implementation backed by ui::mojom::DisplayManager.
+// Screen implementation backed by ui::mojom::ScreenProvider.
 class VIEWS_MUS_EXPORT ScreenMus : public display::ScreenBase,
-                                   public ui::mojom::DisplayManagerObserver {
+                                   public ui::mojom::ScreenProviderObserver {
  public:
   explicit ScreenMus(ScreenMusDelegate* delegate);
   ~ScreenMus() override;
@@ -37,15 +37,15 @@
   bool IsWindowUnderCursor(gfx::NativeWindow window) override;
   aura::Window* GetWindowAtScreenPoint(const gfx::Point& point) override;
 
-  // ui::mojom::DisplayManager:
+  // ui::mojom::ScreenProvider:
   void OnDisplaysChanged(std::vector<ui::mojom::WsDisplayPtr> ws_displays,
                          int64_t primary_display_id,
                          int64_t internal_display_id) override;
 
   ScreenMusDelegate* delegate_;
-  ui::mojom::DisplayManagerPtr display_manager_;
-  mojo::Binding<ui::mojom::DisplayManagerObserver>
-      display_manager_observer_binding_;
+  ui::mojom::ScreenProviderPtr screen_provider_;
+  mojo::Binding<ui::mojom::ScreenProviderObserver>
+      screen_provider_observer_binding_;
 
   DISALLOW_COPY_AND_ASSIGN(ScreenMus);
 };
diff --git a/ui/views/mus/screen_mus_delegate.h b/ui/views/mus/screen_mus_delegate.h
index 0f36fd5..0fe8f7118 100644
--- a/ui/views/mus/screen_mus_delegate.h
+++ b/ui/views/mus/screen_mus_delegate.h
@@ -17,7 +17,7 @@
 
 namespace views {
 
-// Screen implementation backed by ui::mojom::DisplayManager.
+// Delegate for screen implementation backed by ui::mojom::ScreenProvider.
 class VIEWS_MUS_EXPORT ScreenMusDelegate {
  public:
   virtual void OnWindowManagerFrameValuesChanged() = 0;
diff --git a/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js b/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js
index cb06e3576..246e92b9 100644
--- a/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js
+++ b/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js
@@ -88,6 +88,8 @@
       this.classList.remove('closing');
       this.$.dialog.close();
       this.open = false;
+    } else if (this.classList.contains('opening')) {
+      this.fire('cr-drawer-opened');
     }
   },
 });